160 likes | 293 Views
UNITA - IBARRA. TRIGGERS. Paulina Guevara. Concepto. Son bloques de código pl/sql almacenados en la base de datos Se ejecutan automáticamente cuando se produce un evento de inserción, actualización o eliminación (insert, update, delete)
E N D
UNITA - IBARRA TRIGGERS Paulina Guevara
Concepto • Son bloques de código pl/sql almacenados en la base de datos • Se ejecutan automáticamente cuando se produce un evento de inserción, actualización o eliminación (insert, update, delete) • Un disparador está asociado a una tabla y a una instrucción(DML) • Los disparadores son eventos a nivel de tabla
2. Uso de los triggers • Los disparadores pueden emplearse para muchas cosas diferentes, incluyendo: • • El mantenimiento de restricciones de integridad complejas, que no sean posibles con las restricciones declarativas definidas en el momento de crear la tabla.• La auditoría de la información contenida en una tabla, registrando los cambios realizados y la identidad del que los llevó a cabo.• El aviso automático a otros programas de que hay que llevar a cabo una determinada acción, cuando se realiza un cambio en una tabla.
Sintaxis CREATE [OR REPLACE] TRIGGER {BEFORE|AFTER} {DELETE|INSERT|UPDATE [OF col1, col2, . . ., colN][OR {DELETE|INSERT|UPDATE [OF col1, col2, . . ., colN]. . .]}ON table[REFERENCING OLD AS oldname, NEW as newname][FOR EACH ROW [WHEN (condition)]]pl/sql_block . El modificador FOR EACH ROW indica que el trigger se disparará cada vez que se desee hacer operaciones sobre una fila de la tabla. Si se acompaña del modificador WHEN, se establece una restricción; el trigger solo actuará, sobre las filas que satisfagan la restricción.
Tipos de disparadores El suceso de disparo determina el tipo de disparador. Los disparadores pueden definirse para las operaciones INSERT, UPDATE o DELETE, y pueden dispararse antes o después de la operación. Finalmente, el nivel de los disparadores puede ser la fila o la orden.
Utilización de :old y :new en los disparadores con nivel de fila • Un disparador con nivel de fila se ejecuta una vez por cada fila procesada por la orden que provoca el disparo. Dentro del disparador puede accederse a la fila que está siendo actualmente procesada utilizando, para ello, dos seudo-registros, :old y :new.
La cláusula WHEN • La cláusula WHEN sólo es válida para los disparadores con nivel de fila. Si está presente, el cuerpo del disparador sólo se ejecutará para las filas que cumplan la condición especificada en la cláusula. • La cláusula WHEN tiene la forma: • WHEN condición • donde condición es una expresión booleana que será evaluada para cada fila. Se puede hacer también referencia a los registros :new y :old dentro de la condición, pero en ese caso no se utilizan los dos puntos.
Utilización de predicados de los disparadores: INSERTING, UPDATING y DELETING • Dentro de un disparador en el que se disparan distintos tipos de órdenes DML (INSERT, UPDATE y DELETE), hay tres funciones booleanas que pueden emplearse para determinar de qué operación se trata. Estos predicados son INSERTING, UPDATING y DELETING. Su comportamiento es el siguiente:
Requerimientos para el ejemplo Para el ejemplo se necesita crear la tabla employee con los siguientes campos: Emp_id ename Sal job Otra table sal_guide con los siguientes campos Salg_id Job Minsal Maxsal Insertar datos en ambas tablas
Si se desea eliminar (borrar) un trigger, se usa la instrucción: SQL> DROP TRIGGER name; Este trigger impide que se agregue o modifique un empleado con el sueldo mayor o menor que los valores maximo y minimo respectivamente para su cargo. Se agrega la restricción de que el trigger no se dispararán si el cargo es PRESIDENTE. CREATE or replace TRIGGER sal_check1 BEFORE INSERT OR UPDATE OF sal, job ON employee FOR EACH ROW WHEN (new.job <> 'PRESIDENT') DECLARE minsal NUMBER; maxsal NUMBER; BEGIN /* Se obtienen los valores minimo y maximo para el salario de */ /* un cargo determinado, usando la tabla sal_guide */ SELECT minsal, maxsal INTO minsal, maxsal FROM sal_guide WHERE job = :new.job; /* Si el salario del empleado a insertar/modificar esta por */ /* debajo del minimo, o por encima del maximo, se genera */ /* un error. */ IF (:new.sal < minsal OR :new.sal > maxsal) THEN raise_application_error(-20601, 'Salary '||:new.sal|| ' out of range for job '||:new.job||' for employee '|| :new.ename); END IF; END; /
EjeRCICIO: • Un ejemplo de su uso es proporcionar una facilidad de auditoría donde se realiza automáticamente un registro de actividades siempre que se cambia una fila de una tabla. Sin los disparadores de bases de datos esta funcion sería implementada en los programas de seccion de entrada (front-end) que realizan el cambio en la base de datos; sin embargo alguien que se pase por alto el código de los programas de sección de entrada (utilizando SQL*Plus, por ejemplo) no pasaría por las comprobaciones y el procesamiento definidos.
Supóngase que tenemos una tabla llamada SAL (en la que almacenamos los salarios de los empleados de la empresa) y resulta necesario conocer cuándo esta siendo accedida la tabla y el tipo de operación que se realiza. El ejemplo que presentamos a continuación contiene un paquete de muestra que rastrea esta información registrando la hora y la accion ejecutada (UPDATE, DELETE, o INSERT) en la tabla SAL. Mediante una variable global, STAT.ROWCNT, inicializada a cero por el trigger BEFORE e incrementada cada vez que un disparador con nivel de fila es ejecutado, tenemos la informacion estadística que necesitamos salvar en el disparador AFTER.
DROP TABLE stat_tab; CREATE TABLE stat_tab(utype CHAR(8), rowcnt INTEGER, uhour INTEGER); • CREATE OR REPLACE PACKAGE stat IS rowcnt INTEGER; END; • CREATE TRIGGER bt BEFORE UPDATE OR DELETE OR INSERT ON sal BEGIN stat.rowcnt := 0; END;
CREATE TRIGGER rt BEFORE UPDATE OR DELETE OR INSERT ON sal FOR EACH ROW BEGIN stat.rowcnt := stat.rowcnt + 1; END;
CREATE TRIGGER at AFTER UPDATE OR DELETE OR INSERT ON sal DECLARE typ CHAR(8); hour NUMBER; BEGIN IF updating THEN typ := 'update'; END IF; IF deleting THEN typ := 'delete'; END IF; IF inserting THEN typ := 'insert'; END IF; hour := TRUNC((SYSDATE - TRUNC(SYSDATE)) * 24); UPDATE stat_tab SET rowcnt = rowcnt + stat.rowcnt WHERE utype = typ AND uhour = hour; IF SQL%ROWCOUNT = 0 THEN INSERT INTO stat_tab VALUES (typ, stat.rowcnt, hour); END IF; EXCEPTION WHEN dup_val_on_index THEN UPDATE stat_tab SET rowcnt = rowcnt + stat.rowcnt WHERE utype = typ AND uhour = hour; END;