4 BaseDat2 Triggers

Embed Size (px)

DESCRIPTION

Demostración de crear un trigger en modos gráfico y comandos usando pgAdmin III

Citation preview

Triggers (Disparadores)

En PostgreSQL, los triggers son funciones que pueden ser escritas en cualquier lenguaje procedural como PL/pgSQL, PL/Tcl, PL/Perl y PL/Python. Actualmente no es posible escribir un trigger directamente en lenguaje SQL.

Un trigger o disparador es una accin definida en una tabla de la base de datos y ejecutada automticamente por una funcin programada por el DBA o el programador. Esta accin se activar, segn se haya definido, cuando se realice un INSERT, un UPDATE un DELETE en la tabla mencionada.

Un disparador se puede definir de las siguientes maneras:Para que ocurra ANTES de cualquier INSERT,UPDATE DELETE

Para que ocurra DESPUES de cualquier INSERT,UPDATE DELETE

Para que se ejecute una sola vez por comando SQL (statement-level trigger)

Para que se ejecute por cada fila afectada por un comando SQL (row-level trigger)

Esta es la sintaxis del comando SQL que se utiliza para definir un trigger en una tabla.CREATE TRIGGER nombre { BEFORE | AFTER } { INSERT | UPDATE | DELETE [ OR ... ] }ON tabla [ FOR [ EACH ] { ROW | STATEMENT } ]EXECUTE PROCEDURE nombre de funcion ( argumentos )

Antes de definir el trigger se tendr que definir el procedimiento almacenado que se ejecutar cuando el disparador se active.El procedimiento almacenado usado por nuestro trigger se puede programar en cualquiera de los lenguajes de procedimientos disponibles, entre ellos, el proporcionado por default cuando se instala PostgreSQL, el PL/pgSQL. Este lenguaje es el que se utilizar en todos los ejemplos. Podr encontrar mas informacin sobre procedimientos almacenados en el artculo "Procedimientos almacenados y PL/pgSQL"

Caractersticas y Reglas

A continuacin se mencionan algunas de las caractersticas y reglas ms importantes a considerar, cuando se defina un trigger y/o se programe un procedimiento almacenado que sea utilizado por un disparador:El procedimiento almacenado que se vaya a utilizar por el trigger debe definirse e instalarse antes de definir el propio disparador.

Un procedimiento que se vaya a utilizar por un trigger no puede tener argumentos y tiene que devolver el tipo "trigger".

Un mismo procedimiento almacenado se puede utilizar por mltiples triggers en diferentes tablas.

Procedimientos almacenados utilizados por disparadores que se ejecutan una sola vez por comando SQL (statement-level) tienen que devolver siempre NULL.

Procedimientos almacenados utilizados por triggers que se ejecutan una vez por fila afectada por el comando SQL (row-level) pueden devolver una fila de tabla.

Procedimientos almacenados utilizados por triggers que se ejecutan una vez por fila afectada por el comando SQL (row-level) y ANTES de ejecutar el comando SQL que lo lanz, pueden: Retornar NULL para saltarse la operacin en la fila afectada.

devolver una fila de tabla (RECORD)

Procedimientos almacenados utilizados por triggers que se ejecutan AFTER de ejecutar el comando SQL que lo lanz, ignoran el valor de retorno, asi que pueden retornar NULL sin problemas.

En resumen, independendientemente de cmo se defina un trigger, el procedimiento almacenado utilizado por dicho disparador tiene que devolver bien NULL, bien un valor RECORD con la misma estructura que la tabla que lanz dicho trigger.

Si una tabla tiene ms de un disparador definido para un mismo evento (INSERT, UPDATE, DELETE), estos se ejecutarn en orden alfabtico por el nombre del trigger. En el caso de disparadores del tipo BEFORE / row-level, la file retornada por cada disparador, se convierte en la entrada del siguiente. Si alguno de ellos retorna NULL, la operacin ser anulada para la fila afectada.

Procedimientos almacenados utilizados por disparadores pueden ejecutar sentencias SQL que a su vez pueden activar otros disparadores. Esto se conoce como disparadores en cascada. No existe lmite para el nmero de triggers que se pueden llamar pero es responsabilidad del programador el evitar una recursin infinita de llamadas en la que un disparador se llame asi mismo de manera recursiva.

Otra cosa que tenemos que tener en cuenta es que, por cada disparador que definamos en una tabla, nuestra base de datos tendr que ejecutar la funcin asociada a dicho disparador. El uso de triggers de manera incorrecta inefectiva puede afectar significativamente al rendimiento de nuestra base de datos. Los principiantes deberian de usar un tiempo para entender cmo funcionan y as poder hacer un uso correcto de los mismos antes de usarlos en sistemas en produccin.

Variables especiales en PL/pgSQL

Cuando una funcin escrita en PL/pgSQL es llamada por un disparador tenemos ciertas variables especiales disponibles en dicha funcin. Estas variables son las siguientes:NEW. Tipo de dato RECORD; Variable que contiene la nueva fila de la tabla para las operaciones INSERT/UPDATE en disparadores del tipo row-level. Esta variable es NULL en disparadores del tipo statement-level.OLD. Tipo de dato RECORD; Variable que contiene la antigua fila de la tabla para las operaciones UPDATE/DELETE en disparadores del tipo row-level. Esta variable es NULL en disparadores del tipo statement-level.TG_NAME. Tipo de dato name; variable que contiene el nombre del disparador que est usando la funcin actualmente.TG_WHEN. Tipo de dato text; una cadena de texto con el valor BEFORE o AFTER dependiendo de como el disparador que est usando la funcin actualmente ha sido definidoTG_LEVEL. Tipo de dato text; una cadena de texto con el valor ROW o STATEMENT dependiendo de como el disparador que est usando la funcin actualmente ha sido definidoTG_OP. Tipo de dato text; una cadena de texto con el valor INSERT, UPDATE o DELETE dependiendo de la operacin que ha activado el disparador que est usando la funcin actualmente.TG_RELID. Tipo de dato oid; el identificador de objeto de la tabla que ha activado el disparador que est usando la funcin actualmente.TG_RELNAME. Tipo de dato name; el nombre de la tabla que ha activado el disparador que est usando la funcin actualmente. Esta variable es obsoleta y puede desaparacer en el futuro. Usar TG_TABLE_NAME.TG_TABLE_NAME. Tipo de dato name; el nombre de la tabla que ha activado el disparador que est usando la funcin actualmente.TG_TABLE_SCHEMA. Tipo de dato name; el nombre de la schema de la tabla que ha activado el disparador que est usando la funcin actualmente.TG_NARGS. Tipo de dato integer; el nmero de argumentos dados al procedimiento en la sentencia CREATE TRIGGER.TG_ARGV[]. Tipo de dato text array; los argumentos de la sentencia CREATE TRIGGER. El ndice empieza a contar desde 0. Indices invlidos (menores que 0 mayores/iguales que tg_nargs) resultan en valores nulos.

Ejemplos

Una vez que hemos visto la teoria bsica de disparadores nada mejor que unos cuantos ejemplos prcticos para ver como se usan y defininen los disparadores en PostgreSQL. (estos ejemplos han sido comprobados en postgreSQL 9.1 y pgAdmin III v.1.14.2).

1. Ejecute pgAdmin III

Se abrir una ventana como la de la derecha. Puede observar que es la versin 9.1 y que hay tres bases de datos (se usaron en ejercicios anteriores).

El lenguaje PL/pgSQL est instalado por default y lo puede comprobar haciendo lo siguiente:Establezca conexin con la base de datos postgres dando clic sobre ella con el botn izquierdo y expanda su contenido. Vaya al objeto Extensions y expndalo tambin, le mostrar que tiene instalado el lenguaje plpgsql como ilustra la figura de la derecha.

2. Contraiga/colapse el contenido de la base de datos postgres y seleccione la herramienta SQL para ejecutar consultas sobre esta base de datos.

3. Escriba la sentencia que aparece en la imagen de abajo a la izquierda y en el output pane obtendr un resultado similar al de la imagen de abajo a la derecha.

4. Cierre la herramienta SQL y en el panel Object browser seleccione con el botn derecho el objecto Databases (3) y seleccione Refresh. Le aparecer la nueva bases de datos test001 marcada con una x roja, que indica que no tenemos conexin con ella.

Para establecer una conexin con la base de datos test001 slo de un clic sobre ella con el botn izquierdo, y abra nuevamente la herramienta SQL. Las sentencias que se escriban a continuacin afectarn slo a esta base de datos.

5. escriba la sentencia que aparece en la imagen a la derecha, tenga cuidado de escribirla con sus comas, parntesis y punto y como final.

Puede revisar el resultado de la sentencia en el output pane y tambin en el object browser. Expanda la base de datos test001 como ilustra la imagen de la izquierda y encontrar la tabla numeros que se cre mediante la sentencia anterior.

En caso que no aparezca la tabla, seleccione el objeto Tablas con el botn derecho y seleccione la opcin Refresh. Debera aparecer la tabla.

6. Despus tenemos que crear una funcin en PL/pgSQL para ser usada por nuestro disparador. Nuestra primera funcin es la ms simple que se puede definir y lo nico que har es devolver el valor NULL.

Puede ver en el object browser en el objeto Trigger Functions que ya existe la funcin proteger_datos(). Compare esta imagen con la del paso 5 y ver que inicialmente en este objeto haba cero (0) funciones definidas.

7. A continuacin definimos en la tabla numeros un disparador/trigger del tipo BEFORE / row-level para la operacin DELETE. Ms adelante veremos como funciona:

Como se dijo en un inicio, un trigger es una accin que se guarda en una tabla, as que puede corroborar la ejecucin de la sentencia anterior si revisa en el object browser la tabla numeros y observa el SQL paneLa figura siguiente muestra que como parte de la definicin de la tabla tenemos las columnas de la tabla numeros ms el trigger que se estableci en este paso.

8. Ahora vamos a definir una nueva funcin un poco ms complicada y un nuevo disparador en nuestra tabla numeros.

En el object browser2 puede ver que en el objeto Trigger Functions ahora hay dos funciones, proteger_datos y rellenar_datos.

9. Cree el nuevo trigger rellenar_datos y revse su ejecucin en la tabla test001.

Los triggers de la tabla numeros se muestran en la figura de la izquierda

10. Ahora vamos a ver cmo funcionan los triggers que se definieron en la tabla numeros. En la herramienta SQL introduzca la siguiente sentenciaSELECT * from numeros;

El output pane mostrar slo los nombres de las columnas que tiene la tabla numeros.

11. Ejecute una por una cada sentencia siguiente

12. Vuelva a ejecutar la sentencia SELECT * from numeros;

Si bien, slo se introdujeron valores en la columna numero, note que el resto de las columnas tienen sus propios valores. Esto se debe al funcionamiento de los triggers y de los stored procedures - procedimientos almacenados.

13. Teclee y revise el funcionamiento de la siguiente sentencia.

Al ejecutar nuevamente la sentencia SELECT * from numeros; vemos que el valor de 3 en la columna de numero fue sustituido por un valor de 4 y sus respectivos valores de acuerdo a los triggers y los procedimientos almacenados.

Hemos realizado 2 INSERT y 1 UPDATE. Esto significa que por cada uno de estos comandos el sistema ha ejecutado la funcin rellenar_datos(), una vez por cada fila afectada y antes de actualizar la tabla numeros.

Habr comprobado que solamente se ha actualizado la columna numero, pero al mostrar el contenido de la tabla numeros se puede advertir que el resto de columnas (cuadrado, cubo, raiz2 y raiz3) tambin contienen valores.

De esta actualizacin se ha encargado la funcin rellenar_datos() llamada por nuestro disparador. Vamos a analizar lo que hace esta funcin:NEW.cuadrado := power(NEW.numero,2);NEW.cubo := power(NEW.numero,3);NEW.raiz2 := sqrt(NEW.numero);NEW.raiz3 := cbrt(NEW.numero);

RETURN NEW;

Cuando ejecutamos el primer INSERT (numero = 3), el disparador rellenar_datos llama a la funcin rellenar_datos() una vez.

El valor de la variable NEW al empezar a ejecutarse rellenar_datos() es numero=3, cuadrado=NULL, cubo=NULL, raiz2=NULL, raiz3=NULL.

Nuestra tabla todavia no contiene ninguna fila.

A continuacin calculamos el cuadrado, el cubo, la raiz cuadrada y la raiz cubica de 3 y asignamos estos valores a NEW.cuadrado, NEW.cubo, NEW.raiz2 y NEW.raiz3.

El valor de la variable NEW antes de la sentencia RETURN NEW es ahora numero=3, cuadrado=9, cubo=27, raiz2=1.7320, raiz3=1.44225.

Con la sentencia RETURN NEW, retornamos la fila (RECORD) almacenada en la variable NEW, y salimos de la funcin rellenar_datos(). El sistema almacena entonces el RECORD contenido en NEW en la tabla numeros

14. De la misma manera funciona el disparador proteger_datos cuando ejecutamos una sentencia DELETE, antes de borrar algo ejecutar la funcin proteger_datos().Esta funcin retorna el valor NULL y esto significa, segun la regla 6.1 definida en Caractersticas y Reglas lineas arriba, que para la fila afectada no se ejecutar el comanado DELETE. Por eso y mientras este disparador este instalado ser imposible de borrar algo de la tabla numeros.

15. Vamos a continuar complicando las cosas. Primero, vamos a desinstalar nuestros dos disparadores proteger_datos y rellenar_datos.

16. A continuacin crearemos un disparador nico para las sentencias INSERT, UPDATE y DELETE. Este nuevo disparador utilizar una nueva funcin a la que llamaremos proteger_y_rellenar_datos (figura de la izquierda) en la que tendremos que tomar en cuenta qu tipo de comando ha activado el disparador, si queremos retornar el valor correcto. Para ello utilizaremos la variable TG_OP.

El trigger se muestra en la figura de abajo.

La definicin de la tabla la podemos ver en el SQL pane del pgAdmin III, y se muestra en la figura de la derecha.

Y todo seguir funcionando de la misma manera que con los dos disparadores del comienzo. Verifquelo realizando las siguientes acciones en el pgAdmin III. 17. muestre el contenido de toda la tabla

El resultado se muestra abajo a la derecha

18. Inserte en la tabla los valores 6 y 7

19. muestre nuevamente el contenido de la tabla. Deben aparecer los valores iniciales adems de los valores introducidos recientemente con sus clculos respectivos.

20. Ahora haga una actualizacin del registro que tiene el valor de 12, pngale 10.

21. Muestre nuevamente el contenido de la tabla. El registro actualizado se correr a la parte baja de la tabla y los registros actualizados se corrern una posicin hacia arriba, tal y como lo muestra la imagen a la izquierda.

22. Por ltimo, intente hacer la eliminacin de un registro, puede ser cualquiera aunque se escoger el que tiene el valor de 4.

23. El resultado muestra que ninguna fila fue afectada, para comprobarlo, muestre el contenido de la tabla. El resultado debe ser similar al obtenido anteriormente.

Todas las actividades realizadas tambin se pueden hacer en modo comando en la herramienta denominada SQL shell que es uno de los programas del PostgreSQL

Cuando se ejecuta el SQL shell aparecer una ventana similar a la de arriba, en la que se deber aceptar las propuestas que hace.La aplicacin le informa si se desea conectar al Server [localhost], presione [enter].Luego cuestiona si se desea conectar con la base de datos [postgres], presione [enter].Le pregunta si el puerto es [5432], presione [enter].Finalmente se le introduce el username [postgres], presione [enter].Si la contrasea del username, la tiene guardada la aplicacin, ya no se solicitar; pero si no tiene la contrasea guardada, entonces hay que teclearla y presionar [enter].

Introduzca los comandos mostrados en la siguiente figura

El primero es para crear la base de datos test002 y el segundo es para hacer la conexin a dicha base de datos. El lenguaje plpgsql est instalado por default. En caso que no sea as, se introduce el siguiente comando

Ahora se proceder a crear la tabla numeros.

Para crear la primera funcin se introduce lo siguiente.

Y se crea el trigger respectivo

para ver la definicin de la tabla, se introduce...

Se escribe la funcin para actualizar las columnas cuadrado, cubo, raiz2 y raiz3

y el disparador que actuar sobre la tabla

Al revisar la definicin de la tabla se observa que se ha agregado el segundo trigger, como lo muestra la siguiente imagen

Es hora de probar el funcionamiento de las funciones y los triggers. Muestre el contenido de la tabla numeros.

Ahora inserte los valores 2 y 3.

Vuelva a mostrar el contenido de la tabla, debe ser similar a la siguiente imagen.

Ahora haga una actualizacin, el registro con el valor 2, cmbielo a 4.

Vuelva a mostrar el contenido de la tabla, debe ser similar a la siguiente imagen.

Por ltimo, intente hacer el borrado de un registro.

Si despliega nuevamente el contenido de la tabla, se mostrar sin cambio alguno ya que el trigger proteger_datos est evitando que se borre algo de la tabla.Si compara esta parte con la seccin que se hizo en el pgAdmin III, observar que son las mismas instrucciones slo que ahora se est trabajando en modo comando.Para salir del modo comando se introduce el comando \q

ACTIVIDAD1: Se deja como actividad al estudiante realizar a partir del paso 15 en la que se eliminan los dos triggers, se crea la funcin combinada proteger_y_rellenar_datos con su trigger respectivo, y volver a revisar el funcionamiento insertando nuevos valores e intentando borrar algn registro.

ACTIVIDAD2: La puede realizar en modo grfico (pgAdmin III) o en modo comandos (SQL shell).Cree una base de datos llamada facturas y una tabla que se llame detalle_fac que tenga los campos relativos a cdigo de producto, precio unitario, cantidad de piezas, subtotal (resultado de multiplicar la cantidad de piezas por el precio unitario), iva (resultado de multiplicar el subtotal por el 16%), total (suma del subtotal y el iva). Haga que la llave primaria sea la columna cdigo de producto.

Usted debe seleccionar los tipos de datos ms apropiados para cada campo o columna.

Inserte los siguientes datos slo en las columnas relativas a cdigo de producto, cantidad de piezas y precio unitario.

Primer registro: 100, 2 y $10.50

Segundo registro: 110, 3 y $3.33

Haga un desplegado de todos los campos para ver la informacin de la tabla. Slo deben aparecer datos en las tres primeras columnas y primeros dos registros.

Cree la(s) funcion(es) y trigger(s) que necesite para calcular el subtotal, el iva y el total.

Inserte los siguientes datos slo en las columnas relativas a cantidad de piezas y precio unitario.

Tercer registro: 120, 5 y $1.50

Cuarto registro: 130, 4 y $2.25

Haga un desplegado de todos los campos para ver la informacin de la tabla. Ahora deben aparecer datos en cuatro registros. Los primeros dos slo deben tener datos en las primeras tres columnas. Los siguientes dos registros deben tener datos en todas las columnas.

Fuente:http://www.postgresql.org.es/node/301 , artculo del 11/06/2009, por usuario: rafaelmarevisada en Agosto/2012

Apuntes de Bases de Datos II 03/09/12

Valentn Belisario Domnguez Vera