Triggers en PL/SQL Jonathan Medina Gómez Facultad de Ingeniería Universidad de Antioquia Triggers (Disparadores) ● Los triggers son bloques PL/SQL que se ejecutan de manera implícita cuando se están manipulando (INSERT, DELETE, UPDATE) los datos de una tabla. ● Son usados principalmente para establecer reglas de integridad complejas y labores de auditoría. Triggers (Disparadores) II ● La ejecución de un trigger es transaccional, es decir, si un trigger de fila afecta n registros y si uno solo de ellos aborta,entonces todo el proceso se cancela. ● El orden de ejecución de los triggers es el siguiente: 1. Se ejecutan (si los* hay) los triggers BEFORE de operación. 2. Se ejecutan para cada fila: a. (Si los* hay) los triggers BEFORE de fila. b. Se ejecuta la operación DML correspondiente. c. (Si los* hay) los triggers AFTER de fila. 3. Se ejecutan (si los* hay) los triggers AFTER de operación * Si hay varios triggers con idéntica definición (a partir de Oracle 8i), el orden de ejecución entre ellos es “aleatorio”. Un trigger tiene asociado: ● Un Evento: se refiere a la operación que se va a efectuar sobre la tabla (INSERT, DELETE o UPDATE). ● Un Momento: significa cuando se debe disparar el trigger en relación con el evento. Sus posibles valores son AFTER o BEFORE. ● Un Tipo: indica el número de veces que el cuerpo del trigger se debe ejecutar, si por la operación en conjunto (trigger de operación) o por cada fila procesada (trigger de fila). Sintaxis CREATE [OR REPLACE] TRIGGER nombre_trigger momento evento ON tabla [ FOR EACH ROW [ WHEN condición de restricción] ] bloque de PL/SQL ● Cuando el evento es UPDATE, se puede(n) especificar la(s) columna(s) con la palabra OF (si no se especifican, el trigger se dispara con cualquiera de las columnas de la tabla que sea actualizada). El bloque comienza con la palabra DECLARE o BEGIN. Referencia a valores antes y después de la operación Cuando es un trigger de fila, se puede hacer referencia al valor de una columna antes del cambio por medio de : OLD.columna y al valor después del cambio con :NEW.columna. EVENTO VALOR ANTERIOR VALOR NUEVO INSERT NULL El insertado DELETE Valor antes del borrado NULL UPDATE Valor antes de la actualización Valor después de la actualización Ejemplo Trigger de operación Sea la tabla de productos: CREATE TABLE PRODUCTO( codigo NUMBER(6) PRIMARY KEY, precio NUMBER(6)); CREATE OR REPLACE TRIGGER control_inserción BEFORE INSERT ON producto BEGIN IF (TO_CHAR(SYSDATE,'DAY') IN ('SAT','SUN')) OR (TO_NUMBER(TO_CHAR(SYSDATE,'HH24')) NOT BETWEEN 8 AND 18) THEN RAISE_APPLICATION_ERROR(-20506,'Sólo se pueden ingresar productos en horario de oficina'); END IF; END; / La instrucción RAISE_APPLICATION_ERROR abortará la operación de inserción si ésta se intenta realizar en el horario no permitido. Ejemplo Trigger de fila Supóngase la siguiente condición en una empresa: ● ● Ningún empleado puede ganar más que su jefe Supóngase que los jefes se manejan en una tabla separada a la de los empleados Sean las tablas: CREATE TABLE jefe( cedula NUMBER(5) PRIMARY KEY,nombre VARCHAR2(10) NOT NULL, salario NUMBER(8) NOT NULL, secretaria VARCHAR2(10)); CREATE TABLE emp( cedula NUMBER(10) PRIMARY KEY, nombre VARCHAR2(10) NOT NULL, jefe NUMBER(5) NOT NULL REFERENCES jefe,--Clave foránea salario NUMBER(8) NOT NULL); Ejemplo Trigger de fila (II) CREATE OR REPLACE TRIGGER el_jefe_gana_mas BEFORE INSERT ON emp FOR EACH ROW DECLARE salario_jefe jefe.salario%TYPE; BEGIN SELECT salario INTO salario_jefe FROM jefe WHERE cedula = :NEW.jefe; IF salario_jefe < :NEW.salario THEN RAISE_APPLICATION_ERROR(-20505,'Un empleado no puede ganar más que su jefe'); END IF; END; / Ejercicios: Considerar lo siguiente: ● ● ● Si a un empleado le actualizan su salario, que éste no vaya a quedar más alto que el de su jefe. Si a un empleado le cambian de jefe no le vayan a asignar uno que gane menos que él. Si a un jefe le bajan el salario se debe verificar que no quede más bajo que el de alguno de sus subordinados. ¿Puede una persona figurar al mismo tiempo tanto en la tabla de empleados como en la de jefes? ¿Cómo manejar el despido de jefes? ¿Qué hacer con sus subordinados? La cláusula WHEN Sirve para agregar una condición adicional para activar el trigger • Para referirse a NEW y a OLD no se usan los dos puntos dentro de la condición de WHEN Ejemplo. Sean las tablas: CREATE TABLE producto( codigo NUMBER(3) PRIMARY KEY,precio NUMBER(4)); CREATE TABLE auditoria( usuario VARCHAR2(20),cuando DATE, producto NUMBER(6)); Ejemplo WHEN Usando WHEN Sin usar WHEN CREATE or REPLACE TRIGGER quien_baja_precio BEFORE UPDATE OF precio ON producto FOR EACH ROW WHEN (new.precio < old.precio) BEGIN INSERT INTO auditoria VALUES(USER, SYSDATE,old.codigo); END; / CREATE or REPLACE TRIGGER quien_baja_precio BEFORE UPDATE OF precio ON producto FOR EACH ROW BEGIN IF :new.precio < :old.precio THEN INSERT INTO auditoria VALUES(USER, SYSDATE, :old.codigo); END IF; END; / Conclusión: WHEN evita el uso de un IF explícito dentro del código. Ejercicio: Guardar el precio “viejo” y nuevo del producto.