Ordenes y filtros Condicionales

Alcance

Objetos: Work Panels, Web Panels, Procedimientos, Reportes

Lenguajes:  C/SQL, Java, .NET, Visual Basic, Visual FoxPro

DBMS:  DB2/UDB, Informix, Oracle, SQL Server

Interfaces: Web, Win

Introducción

A partir de la versión GeneXus 8.0, es posible restringir tanto los filtros (conocidos normalmente como condiciones de filtro o restricciones) como los órdenes indicados en los objetos GeneXus o en los controles de tipo grid usando una nueva cláusula denominada WHEN. 

 

Esto permitirá tener mejor performance en las consultas que incluyen varios criterios de búsqueda excluyentes entre sí, pues se puede coordinar el orden de búsqueda con las condiciones adecuadas.

 

Descripción

Condiciones de un Filtro

Es posible restringir los filtros especificados a nivel del comando For Each, de las Conditions generales de un objeto o de un grid.  De esta forma, ese filtro se aplicará únicamente cuando se cumpla la resticción. Si la misma no se cumple, el filtro no seaplica.

 

La sintaxis de las condiciones (WHERE, etc.) en la versión GeneXus 8.0  es:

 

Condition [WHEN <Constraint>];

 

Siendo:

Condition una condición GeneXus.

Constraint la condición que habilita Condition.

 

Las condiciones de filtro condicionales son aditivos (con AND) entre ellas y puede ocurrir que no aplique ninguna restricción si todas las condiciones correspondientes son falsas.

 

Para que una restricción condicional pueda ser generada como tal, se debe estar en una arquitectura Cliente/Servidor y la Condition tiene que ser "evaluable" por el DBMS que se está utilizando, es decir, GeneXus tiene que saber cómo escribir la Condition en el lenguaje propio del DBMS utilizado.

 

Si no se puede generar como tal (porque el generador destino no lo soporta o porque la condición no puede ser escrita en el lenguaje del DBMS) se transformará en un filtro "común" sustituyendo el WHEN por un OR.  Además, se generará el mensaje de código spc0053 -‘Unsupported conditional constraint "%1" changed to standard constraint %2.’-  en el Diagrama de Navegación.  (La especificación en Diseño asume una generación SQL en un DBMS no determinado)

 

Listado de Navegación

Cuando se definen filtros condicionales el diagrama de navegación lo muestra como una Constraint condicional y no participa en la determinación del Start From/Loop While.

 

Ejemplo:

 

 

 

Sentencias Generadas.

Las sentencias generadas para los filtros condicionales son similares a las generadas en el caso de filtros estándar (sin la clásula WHEN).  La diferencia principal es que son estáticas, es decir se tienen todos los strings posibles y de acuerdo a las condiciones se concatenan los que correspondan.  Además, los valores de las variables siempre van instanciados. Cuando no se utiliza la cláusula WHEN la sentencia generada tiene un parámetro remplazable (aparece como ‘?’)

 

Ejemplo

 

·         El filtro CliDir >= &CliDir or not null(&CliDir) genera la sentencia:

 

SELECT [CliDir], [CliNom], [CliId] FROM [CLIENTES] (NOLOCK) WHERE [CliDir] = ? or   (?=' ') ORDER BY [CliId] 

 

·         Si ese filtro se hace condicional: CliDir >= &CliDir WHEN not null(&cliDir), se generarán dos sentencias:

 

1.      la que se ejecutará cuando la variable &CliDir sea nula:

SELECT [CliNom], [CliId] FROM [CLIENTES] (NOLOCK)  ORDER BY [CliId]

 

2.      la que se ejecutará cuando la variable &CliDir tenga valor:

SELECT [CliDir], [CliNom], [CliId] FROM [CLIENTES] (NOLOCK)  WHERE [CliDir] = 'Miguelete 1234' ORDER BY [CliId]'

 

 

Ordenes condicionales

Es posible especificar órdenes de navegación alternativos dependiendo de las necesidades de la aplicación. La sintáxis correspondiente es:

 

[ORDER] <OrderAttList> [WHEN <Constraint1>]

[ORDER <OrderAttList1> [WHEN <Constraint2>]

...

 

<OrderAttListX> es una lista de atributos separados por espacios o comas que indican el orden de navegación. Si se desea un orden descendente por alguno de los atributos se lo encierra entre paréntesis curvos.

 

<ConstraintX> es la condición que habilita el <OrderAttList> correspondiente.

 

Si ninguna de las Constraints  es verdadera y no existe un Order incondicional (sin la cláusula WHEN) el orden de navegación es indefinido. Indefinido, en este caso, significa que no se indica un orden por lo que el orden empleado puede variar de DBMS en DBMS e, inclusive, en ejecuciones sucesivas.

 

Si más de una de las Constraints es verdadera, se toma el orden de la primera cláusula ORDER definida, por este motivo, debería ser el orden preferido para las consultas.

 

Si se especifican órdenes condicionales pero el generador no lo soporta, el órden de navegación será el especificado como orden incondicional o, si no lo hubiera, la llave primaria de la tabla base del grupo.  Además, se generará el mensaje de código spc0054 -‘ Unsupported conditional order %2. Using default order in %1.’-en el diagrama de navegación. (La especificación en Diseño asume una generación SQL en un DBMS no determinado)

 

No se soportan ordenes condicionales cuando se realizan Breaks. Se generará el mensaje de código spc0055 -‘ Conditional order in group starting at line %1  not allowed (Break group).’-en el diagrama de navegación.

 

Consideraciones generales

·         Sólo aplican a generadores que utilizan SQL como método de acceso a la base de datos

 

·         Si el Constraint contiene atributos, estos son considerados como instanciados. En otras palabras, el Constraint se evalúa antes de iniciar la navegación y no cambia durante ésta.

 

Performance –

Como se comentó antes, el uso de la cláusula when, implica que la sentencia se generará estática.  Eso significa que, se realizará un Prepare de cada sentencia diferente que se ejecute y que como se conoce el valor de los parámetros el manejador de base de datos puede optimizarse mejor la estrategia de acceso utilizada.

Cuando no se utiliza la cláusula when, la sentencia es dinámica e incluye los parámetros que serán remplazables.  Eso significa que se realizará un único prepare que se reutilizará en todas las ejecuciones de la misma.

A priori no puede anticiparse si un mecanismo u otro será mas performante ya que depende de muchos factores, entre los que se destaca la cantidad de registros, la distribución de los datos y la complejidad de la consulta.

·          

·         Se recomienda que los grupos con orden o filtros  condicionales no sean utilizados dentro de loops de alto nivel de ocurrencias porque el tiempo de "analisis" que, en cada ejecución, debe hacer el DBMS pueda ser bastante alto para estas situaciones.

 

Fuera de lo mencionado antes, se esperan mejoras sensibles en la performance de consultas del tipo: "digame qué datos tiene que lo busco" ya que con las condiciones adecuadas se pueden hacer coordinar los filtros con el orden de búsqueda.

 

Ejemplos

Ejemplo 1

El siguiente es un ejemplo de una condición de filtro:

 

ClienteNombre LIKE &ClienteNombre

          WHEN NOT null(&ClienteNombre);

ClienteCedula >= &ClienteCedula

          WHEN NOT null( &ClienteCedula);

 

La forma de interpretar el código anterior es:

Si la variable &ClienteNombre tiene algún valor entonces GeneXus aplicará el filtro ClienteNombre LIKE &ClienteNombre. Si, además, la variable &ClienteCedula tiene algún valor también aplicará el filtro ClienteCédula >= &ClienteCedula en una relación de AND con los demás filtros. 

Si ninguna variable tiene valor, entonces no se aplicará ningun filtro.

 

Ejemplo 2:

 

For each ClienteNombre WHEN NOT null(&ClienteNombre)

          Order ClienteCedula WHEN NOT null( &ClienteCedula)

          ...

Endfor

 

En este For Each, la navegación se realizará ordenada por ClienteNombre si la variable &ClienteNombre tiene un valor. Si no lo tiene, entonces el órden será por ClienteCédula si &ClienteCedula tiene un valor. En última instancia, si ninguna de las condiciones anteriores se cumple, la navegación se realizará en un orden indefinido.

 

For each ClienteNombre WHEN NOT null(&ClienteNombre)

          Order ClienteCedula WHEN NOT null( &ClienteCedula)

          Order ClienteId

          ...

Endfor

 

En este otro For Each del ejemplo, los órdenes de navegación son iguales a los del primero a excepción del caso en que ninguna de las Conditions se cumpla por existir un Order incondicional. La navegación se realiza por el Order incondicional ClienteId en este caso.