martes, 10 de abril de 2018

Triggers de Forms relacionados con las Consultas

Objetivos:

 Explicar los procesos implicados en las consultas de los bloques de datos.
 Describir el alcance de los Triggers de Consultas (Query Triggers).
 Crear Triggers para condicionar las consultas.
 Crear Triggers para complementar los resultados de una consulta.
______________________________________________________________________________________
Procesamiento de Consultas.
Por lo general, los Triggers se asocian a una consulta de dos maneras:
 Un Trigger se dispara debido al proceso de consulta en sí.
   Ejemplo: Pre-Query Post-Query.
 Un evento puede desencadenar un Trigger en el modo Enter-Query, si la propiedad Fire in Enter-Query Mode del Trigger está activada.

Los Triggers de Consultas, Pre-Query y Post-Query, se activan debido al proceso de consulta, y normalmente se definen en el bloque donde se realiza dicha consulta.

Con estos Triggers se puede agregar funcionalidad al procesamiento normal de registros, o posiblemente abandonar una consulta antes de que se ejecute, si ciertas condiciones no son cumplidas.

Procesamiento de Consultas en Forms.
Cuando el usuario o algún Built-in inicia una consulta en un bloque de datos, se producen los siguientes eventos:
1. En el modo Enter-Query, Forms activa el Pre-Query (si dicho trigger está definido).
2. Si el Pre-Query tiene éxito, Forms crea la sentencia SELECT, basada en cualquier criterio existente en el bloque (introducido por el usuario o por el Pre-Query).
3. La consulta es ejecutada.
4. Forms se encarga de copiar los valores obtenidos de la tabla base a los Items del bloque.
5. Forms activa el Trigger  Post-Query. Si dicho Trigger falla, el registro se elimina del bloque.
6. Si luego del Trigger Post-Query el registro es cambiado, Forms realiza una validación del mismo.
7. Los pasos del 4 al 7 se repiten para todos los registros de la consulta.

Sentencias SELECT emitidas durante el procesamiento de consultas.
Si no ha alterado el procesamiento por defecto de las consultas, Forms emite una instrucción SELECT cuando desea recuperar o contar registros.
  SELECT  base_columnbase_column, ... , ROWID
INTO 
:base_item,  :base_item,  ... , :
ROWID
FROM 
base_table
WHERE  (default_where_clause OR onetime_where_clause)
AND  (example_record_conditions)
AND  (query_where_conditions)
ORDER BY 
default_order_by_clause | query_where_order_by

  SELECT  COUNT(*)FROM  base_table
WHERE  (default_where_clause OR onetime_where_clause)
AND  (example_record_conditions)AND  (query_where_conditions)ORDER BY  default_order_by_clause | query_where_order_by
Nota: La barra vertical (|) en la cláusula ORDER BY indica que cualquiera de las dos posibilidades puede estar presente. Forms recupera el ROWID solo cuando la propiedad Key Mode del bloque está configurada en Unique (valor predeterminado). Toda la cláusula WHERE es opcional. La cláusula ORDER BY también es opcional.
______________________________________________________________________________________
Cláusulas WHERE y ORDER BY.
Las cláusulas WHERE y ORDER BY de una sentencia SELECT de tabla base se derivan de varias fuentes. Es importante saber cómo estas distintas fuentes interactúan.

Las fuentes de la cláusula WHERE.
 La propiedad WHERE Clause (establecida en Forms Builder o configurando la propiedad DEFAULT_WHERE_CLAUSE mediante programación).
 La propiedad de bloque ONETIME_WHERE (establecida mediante programación).
 Cuadro de diálogo Query/Where.

Si hay más de una fuente presente, las diferentes condiciones se vincularán y usarán con un operador AND. Si la cláusula WHERE y la cláusula ONETIME_WHERE están presentes, solo se utiliza una: la cláusula ONETIME_WHERE para la primera ejecución de la consulta y la cláusula WHERE para las ejecuciones posteriores.


Propiedad ONETIME_WHERE:
En los casos en que desee restringir la consulta solo una vez, mediante programación puede establecer la propiedad ONETIME_WHERE en un bloque. Esto especifica una cláusula WHERE que estará vigente solo para la primera consulta emitida en el bloque después de establecer esa propiedad.

Ejemplo:
Desde el bloque ORDER_ITEMS, desea mostrar el bloque INVENTORIES, que esta en una ventana (Window) separada. Cuando el bloque es inicialmente mostrado, debe presentar información sobre la existencia del producto seleccionado en el bloque ORDER_ITEMS. Sin embargo, cuando esta información inicial es mostrada, se desea que los usuarios puedan consultar la existencia de cualquier producto. Para ello, se podría codificar la propiedad ONETIME_WHERE en algún botón :
Set_Block_Property('INVENTORIES', ONETIME_WHERE, 'product_id = '||:ORDER_ITEMS.PRODUCT_ID);
Go_block('INVENTORIES');
Execute_Query;

Las fuentes de la cláusula ORDER BY.
 La Propiedad ORDER BY Clause del bloque.
 Cuadro de diálogo Query/Where.

Una cláusula ORDER BY especificada en el cuadro de diálogo Query/Where reemplaza el valor de la propiedad ORDER BY Clause del bloque.

Nota: Puede usar el Built-in SET_BLOCK_PROPERTY  para cambiar las cláusulas WHERE y ORDER BY en tiempo de ejecución.

______________________________________________________________________________________
Trigger Pre-Query.

Este Trigger puede ser definido a nivel de bloque o superior. Se activa para todas las consultas (global o restringida por algún filtro), justo antes de que Forms ejecute la consulta. Puede usar Pre-Query para:
 Validar las condiciones de consulta del usuario y así detener el proceso de consulta si ciertas condiciones no son satisfactorias o no aplican.
 Añadir criterios a la consulta asignando valores a los items de la tabla base.

Ejemplo:
BEGIN
IF TO_CHAR(:ORDERS.ORDER_ID)||TO_CHAR(:ORDERS.CUSTOMER_ID) IS NULL THEN
MESSAGE('You must query by Order ID or Customer ID');
RAISE form_trigger_failure;
END IF;
END;
/*
El anterior es un ejemplo de un Trigger Pre-Query en el bloque ORDERS que impide procesar una consulta si los campos ORDER_ID y CUSTOMER_ID están nulos. Esto evita consultas muy grandes.
*/
Nota: Pre-Query es útil para asignar valores pasados desde otros módulos de Oracle Forms Developer, de modo que la consulta esté relacionada con los datos en cualquier parte de la sesión.
______________________________________________________________________________________
Trigger Post-Query.

Este Trigger al igual que el Pre-Query se define a nivel de bloque o superior. Se activa (ejecuta) por cada registro retornado por la consulta. Tenga en cuenta que el Trigger se dispara solo en la recuperación inicial de un registro, no cuando el registro es mostrado en pantalla como resultado de mover la barra de desplazamiento (Scroll Bar).

Use Post-Query de la siguiente manera:
 Para rellenar Items que no sean de base de datos (nondatabase) a medida que se devuelven los registros de una consulta.
 Para calcular estadísticas.

Ejemplo:
BEGIN
SELECT COUNT(order_id)
INTO :ORDERS.lineitem_count
FROM ORDER_ITEMS
WHERE order_id = :ORDERS.order_id;
END;

/*El anterior es un ejemplo de un Trigger Post-Query en el bloque ORDERS, en él, se selecciona la cantidad total de líneas de pedido para el pedido actual y muestra este número como un valor de resumen en el Item (nondatabase) :Lineitem_count.*/
______________________________________________________________________________________
Uso de la Sentencia SELECT en Triggers.

El ejemplo anterior rellena el Item Lineitem_Count a través de la cláusula INTO. Notar como se requieren dos puntos delante de las variables de Forms Builder para distinguirlas de las variables de PL/SQL y las columnas de la base de datos.

Aquí algunas directrices relacionadas a las sentencias SELECT en PL/SQL:
 Las variables de Forms Builder son precedidas por dos puntos.
 La consulta debe devolver un solo registro, de lo contrario se genera una excepción que finaliza la parte ejecutable del bloque. Por lo general, se hace coincidir un Item de Forms con un valor de columna.
 Es recomendable codificar manejadores de excepciones (Code Exception Handlers) en su bloque PL/SQL para tratar las posibles excepciones que podrían surgir por las sentencias SELECT.
 La cláusula INTO es obligatoria y requiere una variable de recepción para cada columna o expresión seleccionada. Puede usar variables PL/SQL, Items de Forms o variables globales en la cláusula INTO.
 ORDER BY y otras cláusulas que controlan consultas de múltiples filas no son relevantes (a menos que sean parte de un de Cursor explícito).
______________________________________________________________________________________
Procesamiento de la Matriz Consulta (Query Array).

Por defecto, Forms procesa los registros uno a uno. Con el procesamiento matriz, una estructura (matriz) que contiene múltiples registros se envía o se devuelve desde el servidor para su procesamiento.
Forms admite el procesamiento de búsqueda matriz y el procesamiento DML matriz. Para consultas y operaciones DML, puede determinar el tamaño de la matriz para optimizar el rendimiento según sus necesidades. Esta lección se centra en el procesamiento de consultas matriz.

Habilitar el procesamiento matriz para consultas:
1. En el menú:
--Seleccione Editar (Edit)> Preferencias (Preferences).
--Haga clic en la pestaña Runtime.
--Seleccione la casilla de Procesamiento de Matrices (Array Processing).
2. Configuración de propiedades:
--Seleccione el Bloques de Datos  en cuestión y despliegue sus propiedades (F4).
--En la categoría Registros (Records), establezca la propiedad Tamaño Matriz de Consulta (Query Array Size) en un número que represente la cantidad de registros en la matriz para el procesamiento en cuestión.
 Tamaño Matriz de Consulta (Query Array Size): esta propiedad especifica el número máximo de registros que Forms deben obtener de la base de datos a la vez. Si se establece en cero, el tamaño de la matriz de consulta se establece de manera predeterminada en la cantidad de registros que se muestran en el bloque.
Un tamaño de 1 proporciona el tiempo de respuesta más rápido, porque Forms recupera y muestra solo un registro a la vez. Por el contrario, un tamaño de 10 obtiene hasta diez registros antes de mostrar alguno de ellos, sin embargo, mientras más grande el tamaño menor el tiempo total de procesamiento esto porque se requieren menos llamadas a la base de datos.
 Query All Records: especifica si todos los registros que coinciden con los criterios de la consulta se deben buscar en el bloque de datos cuando se ejecuta una consulta.
--: recupera todos los registros de la consulta.
--No: obtiene la cantidad de registros especificados por la propiedad del bloque Query Array Size.
______________________________________________________________________________________
Codificando Triggers para el modo Enter-Query.

Algunos Triggers que se activan cuando el Forms está en modo Normal (durante se le da entrada y al guardar los datos) también pueden ser disparados en el modo Enter-Query. Debe considerar el tipo de Trigger y las acciones en estos casos.

Propiedad Disparar en Modo Enter-Query (Fire in Enter-Query Mode).
Esta propiedad es la que determina si Forms dispara el Trigger si el evento asociado ocurre en el modo Enter-Query. No todos los Triggers pueden hacer esto; consulte la Ayuda en línea de Forms Builder para que tenga la lista completa de los que lo permiten.
De manera predeterminada, la propiedad Fire in Enter-Query Mode está en para los Triggers que la contienen. Si desea que estos Triggers sólo disparen en Modo Normal debe establecer dicha propiedad en No.

Nota: en todo momento puede verificar el modo actual del Form con :SYSTEM.MODE el cual puede contener los siguientes valores: NORMAL, ENTER-QUERY, QUERY.

Ejemplo:
Si proporciona un botón para que el usuario invoque un LOV, y el LOV debe servir como filtro o como criterio de búsqueda y a la vez se usa para introducir nuevos datos, entonces el Trigger When-Button-Pressed debe activarse en ambos modos.
IF SHOW_LOV('Customers') THEN
   MESSAGE('Selection successful');  
END IF;
--
Variable :SYSTEM.MODE.
Cuando un Trigger se dispara tanto en modo Enter-Query como en modo Normal, es posible que necesite conocer el modo actual en momento de ejecución por los siguientes motivos:
 El Trigger necesita realizar diferentes acciones dependiendo del modo.
 Algunos subprogramas built-in no se pueden usar en el modo Enter-Query.
La variable del sistema de solo lectura, MODE, almacena el modo actual del Form. Su valor (siempre en mayúsculas) es uno de los siguientes:
Valor Definición
NORMAL Form está en modo de procesamiento Normal.
ENTER-QUERY Form está en modo Enter Query.
QUERY Form está en modo de extracción (Fetch-processing mode), lo que significa que Forms está actualmente realizando una extracción. (Por ejemplo, este valor siempre ocurre en el Trigger Post-Query).


Ejemplo:
Tenga en cuenta el siguiente Trigger When-Button-Pressed para el botón Consulta.
Si el usuario hace clic en el botón en el modo Normal, dicho Trigger coloca el Forms en modo Enter-Query (usando el built-in ENTER_QUERY). De lo contrario, si ya está en el modo Enter-Query, el botón ejecuta la consulta (usando el built-in EXECUTE_QUERY).
IF :SYSTEM.MODE = 'NORMAL' THEN
  ENTER_QUERY;
ELSE
  EXECUTE_QUERY;
END IF;

Uso de built-ins en el modo Enter-Query.
Algunos built-ins son ilegales si se ejecuta un Trigger en modo Enter-Query. Nuevamente, consulte la Ayuda en línea de Forms Builder, el cual especifica los built-ins que pueden ser usados en este modo.

Una restricción general es que en el modo Enter-Query el usuario no puede navegar a otro registro en el Form actual. Entonces, cualquier built-in que potencialmente permita esto es ilegal. Estos incluyen GO_BLOCK, NEXT_BLOCK, PREVIOUS_BLOCK, GO_RECORD, NEXT_RECORD, PREVIOUS_RECORD, UP, DOWN, OPEN_FORM y otros.
______________________________________________________________________________________
Cambiando el Procesamiento de Consultas Predeterminado.


Puede usar ciertos Triggers transaccionales para reemplazar el proceso de guardado (commit) predeterminado. Algunos de los Triggers transaccionales también pueden ser usados para reemplazar el procesamiento de consultas predeterminado.

Puede invocar built-ins “Do-the-right-thing” desde Triggers transaccionales para aumentar el procesamiento de consultas predeterminado. Los built-ins “Do-the-right-thing” realizan las mismas acciones que el proceso predeterminado. Con el uso de ellos puede complementar el procesamiento predeterminado con su propio código.

Triggers transaccionales adicionales para el procesamiento de consultas.
Sus usos:
Los Triggers transaccionales para el procesamiento de consultas están destinados principalmente a acceder ciertas fuentes de datos distintas de Oracle. Sin embargo, también pueden ser usados para implementar una funcionalidad especial al aumentar el procesamiento de consultas predeterminado en una base de datos Oracle.

Características:
Trigger Características
On-Close Se activa  cuando Forms cierra una consulta (Más que reemplazar, su función es Aumentar el procesamiento predeterminado).
On-Count Se activa cuando Forms generalmente realiza el procesamiento de conteo de registros que coinciden con las condiciones de consulta.
On-Fetch Se activa cuando Forms realiza un fetch para un conjunto de filas. Puede usar CREATE_QUERIED_RECORD (built-in usado principalmente en aplicaciones que usan triggers transaccionales que interactúan con bases de datos distintas a Oracle) para crear registros consultados si desea reemplazar el procesamiento de búsqueda predeterminado. El Trigger continúa ejecutando hasta que:
 Cuando no se crea al menos un registro durante una de las ejecuciones del trigger. Cuando la consulta es cerrada por el usuario o por el uso del built-in ABORT_QUERY.
 Cuando ocurre la excepción FORM_TRIGGER_FAILURE en el trigger.
Pre-Select Se dispara justo después de construir la sentencia SELECT del bloque en función de las condiciones de consulta, pero antes de emitir esta sentencia.
On-Select Se dispara en lugar de emitir la sentencia SELECT del bloque (este trigger reemplaza el OPEN CURSOR, el análisis (parse) y las fases de ejecución de una consulta).
Post-Select Se activa después de haber construido y emitido el SELECT, pero antes de recuperar los registros.
______________________________________________________________________________________
Obteniendo Información de la Consulta en Tiempo de Ejecución.
Puede usar Variables de Sistema en conjunto con los built-ins para obtener información sobre consultas.

:SYSTEM.MODE: Use esta variable de sistema para obtener el modo actual de Forms. Los tres valores son NORMAL, ENTER_QUERY y QUERY. Esta variable del sistema fue discutida previamente.

:SYSTEM.LAST_QUERY: Es útil para para obtener el texto de la sentencia SELECT que fue ejecutada por última vez por Forms. Si un usuario ha introducido condiciones de consulta en el bloque, la forma exacta de la sentencia SELECT depende de cuándo se utiliza esta variable de sistema.
Si la variable de sistema se usa antes de que Forms haya ejecutado implícitamente el built-in SELECT_RECORDS, la sentencia SELECT contiene variables bind (por ejemplo, ORDER_ID = :1). Si se utiliza después de que Forms haya ejecutado implícitamente SELECT_RECORDS, la sentencia SELECT contiene los valores de búsqueda reales (por ejemplo, ORDER_ID = 102). La variable del sistema contiene variables bind durante el Trigger Pre-Select y los valores de búsqueda reales durante el Trigger Post-Select.
A diferencia de la mayoría de las variables del sistema, SYSTEM.LAST_QUERY puede contener una mezcla de mayúsculas y minúsculas

Usando GET_BLOCK_PROPERTY y SET_BLOCK_PROPERTY.
Las siguientes propiedades de bloque pueden ser útiles para obtener información de consulta. Solo se pueden establecer las propiedades marcadas con un asterisco.
 DEFAULT_WHERE (*)
 ONETIME_WHERE (*)
 ORDER_BY (*)
 QUERY_ALLOWED (*)
 QUERY_HITS (*)
 QUERY_OPTIONS
 RECORDS_TO_FETCH

Las siguientes propiedades de Items pueden ser útiles para obtener información de consulta. Solo se pueden establecer las propiedades marcadas con un asterisco.
CASE_INSENSITIVE_QUERY (*)
QUERYABLE (*)
QUERY_ONLY (*)
QUERY_LENGTH
______________________________________________________________________________________
Resumen.
En esta publicación, debes haber aprendido que:
El procesamiento de consultas incluye los siguientes pasos:
1. El Trigger Pre-Query se dispara.
2. Se construye la sentencia SELECT.
3. Se realiza la consulta.
4. Los registros son extraídos y mostrados (Fetch) en el bloque.
5. Los registros son marcados como validos.
6. El Trigger Post-Query se dispara.
7. Se produce la validación de los Items y registros (Records) si el registro ha cambiado (debido a un Trigger).
8. Los pasos del 4 al 7 se repiten hasta que todo se haya recuperado.

El proceso de consulta: antes de comenzar la consulta, el Trigger Pre-Query se activa una vez para cada consulta. Luego, la sentencia de consulta se construye y se ejecuta. Para cada registro recuperado por la consulta, el registro se extrae en el bloque (Fetch) y se marca como válido, el Trigger Post-Query se activa para ese registro, y la validación de  Item y registro (Record) se produce si un Trigger lo ha cambiado.

______________________________________________________________________________________
Fuente: Oracle Forms Developer 10g: Build Internet Applications.