You are on page 1of 38

Disparadores en ORACLE

Bibliografa Oracle Database Concepts - 10g Release 2 (10.2) (Octubre 2005) Oracle Database Application Developer's Guide Fundamentals 10g Release 2 (10.2) (Noviembre 2005) scar Daz Universidad del Pas Vasco (UPV) Bases de Datos Activas

Introduccin
PL/SQL: lenguaje de programacin estructurado en bloques Bloques: unidad mnima en PL/SQL
Soportan DML y DDL Annimos / Con nombre TRIGGERS
DECLARE optional BEGIN required EXCEPTION optional END; / required

Disparadores (triggers) en Oracle: bloques de cdigo que son implcitamente invocados cuando algo sucede CREATE TRIGGER Triggers VS Procedimientos NombreTrigger
Ejecucin Implcita: Disparar No admiten argumentos
BEFORE INSERT ON StarsIn DECLARE .. END; TRIGGER / CREATE PROCEDURE Get_emp_rec (Emp_number IN Emp_tab.Empno%TYPE) AS BEGIN - - - - END; /

Aplicaciones:
Restricciones (Constraints) Auditoras Informar de Eventos

PROCEDIMIENTO

Introduccin

3 Tipos
DML/DDL (Fila/Sentencia, BEFORE/AFTER) INSTEAD OF SYSTEM

Estructura General de un Disparador

CREATE [OR REPLACE] TRIGGER nombre {BEFORE | AFTER | INSTEAD OF} Temporalidad del Evento {INSERT | DELETE | UPDATE [OF <atributo>]} ON <tabla>

Evento

[WHEN condicin] Granularidad [FOR EACH ROW | STATEMENT]

Condicin

BEGIN

cuerpo del trigger


END;

Accin

Temporalidad del Evento: AFTER / BEFORE


BEFORE Ejecutan la accin asociada antes de que la sentencia sea ejecutada
Decidir si la accin debe realizarse Utilizar valores alternativos para la sentencia
CREATE TRIGGER NombreTrigger BEFORE Insert ON NombreTabla .
Los de tipo BEFORE son mejores en trminos de rendimiento

AFTER Ejecutan la accin asociada despus de que se haya ejecutado la sentencia


CREATE TRIGGER NombreTrigger AFTER Insert ON NombreTabla .

Granularidad del Evento: FOR EACH ROW / STATEMENT


A NIVEL DE FILA: ROW TRIGGERS

Ejecutan la accin asociada tantas veces como filas se vean afectadas por la sentencia que lo dispara
Si ninguna fila se ve afectada, no se dispara
CREATE TRIGGER NombreTrigger BEFORE Insert ON NombreTabla FOR EACH ROW .

Utilizar cuando la accin depende de la sentencia que produjo el evento o de las filas afectadas

Granularidad del Evento: FOR EACH ROW / STATEMENT A NIVEL DE SENTENCIA: STATEMENT TRIGGERS Ejecutan una nica vez la accin asociada, independientemente del nmero de filas que se vean afectadas por la sentencia
CREATE TRIGGER NombreTrigger BEFORE Insert ON NombreTabla [STATEMENT]

Utilizar cuando la accin NO depende de la sentencia que produjo el evento o de las filas afectadas Comprobaciones de seguridad a cerca del usuario o el
momento concreto Generar registros de auditora

Condicin
Expresa una condicin que debe cumplirse en el momento de producirse el evento, para que la accin sea ejecutada.
WHEN persona.nombre = 'pepe' OR persona.edad > 35

Se puede utilizar cualquier combinacin de operadores lgicos (AND, OR, NOT) y relacionales (< <= > >= = <>). No se puede especificar una condicin para los disparadores a nivel de sentencia (STATEMENT) ni los disparadores INSTEAD OF Debe ser una consulta SQL y no puede contener subconsultas SELECT * FROM Productos
WHERE PrecioUnidad IN (SELECT PrecioUnidad FROM DetallePedido WHERE Descuento = 0 .25)

Orden de Ejecucin Una sentencia SQL puede disparar varios TRIGGERS. La activacin de un trigger puede disparar la activacin de otros triggers.
1. 2. Triggers Before (nivel de sentencia) Para cada fila: 1. Trigger Before (a nivel de fila) 2. Ejecuta la Sentencia 3. Triggers After (a nivel de fila) Triggers After (a nivel de Sentencia)

3.

Se compromete o se deshace toda la transaccin El orden de ejecucin de disparadores del mismo tipo es indeterminado

Estructura General de un Disparador


CREATE OR REPLACE TRIGGER Control_Docencia AFTER DELETE ON Profesores WHEN old.nombre LIKE %Juan% FOR EACH ROW

Evento Condicin

DECLARE var VARCHAR2(50); BEGIN SELECT a.nombre INTO var FROM Asignaturas a WHERE REF(a) = :NEW.asignatura; DELETE FROM Asignaturas WHERE nombre = var END; /

Accin

Correlation Identifiers: Valores OLD y NEW


Tipo especial de variable PL/SQL tratada como un registro de tipo tabla_modificada%ROWTYPE Con OLD.nombre_columna referenciamos:
Al valor que tena la columna antes del cambio debido a una modificacin (UPDATE) Al valor de una columna antes de una operacin de borrado sobre la misma (DELETE) Al valor NULL para operaciones de insercin (INSERT)

Con NEW.nombre_columna referenciamos:


Al valor de una nueva columna despus de una operacin de insercin (INSERT) Al valor de una columna despus de modificarla mediante una sentencia de modificacin (UPDATE) Al valor NULL para una operacin de borrado (DELETE)
SINTAXIS

Condicin (WHEN .) En el cuerpo del disparador

OLD, NEW :OLD, :NEW

ROW TRIGGER: ejemplo


Cuando se borre en la tabla persona alguna persona que se llame pepe o cuya edad sea mayor de 35 aos, eliminar tambin dicha persona de la tabla persona2

Persona Cod Nombre Edad


C1 C2 C3 C4 C5 Mara Pepe Pepe Luisa Pepe 25 40 45 48 22

Persona2 Cod
C1 C2 C3 C4 C5

Nombre Edad
Mara Pepe Pepe Luisa Pepe 25 40 45 48 22

DELETE FROM persona WHERE cod in (C1,C3,C4)

Borra C3 y C4 de persona2

STATEMENT TRIGGER: ejemplo


Cuando se borre en la tabla socio emitir un mensaje indicando que no se pueden borrar socios

Socio
Cod Nombre Fecha_ant
S1 S2 S3 S4 S5 Mara Pepe Pepe Luisa Pepe ...... ...... ...... ...... ......

DELETE FROM socio WHERE nombre = Pepe

Borra 3 tuplas y se emite un nico mensaje

Triggers DML Disparados por sentencias DML: INSERT, UPDATE o DELETE Todas las filas o slo algunas (WHEN)
LIBROS

ESTADSTICAS

ISBN 100-09-89 -----

GENERO Novela ----

TTULO El Quijote ----

GENERO Novela Infantil

TOTAL_LIBROS 50 15

CREATE OR REPLACE TRIGGER UpdateEstadisticasGenero

AFTER INSERT OR DELETE OR UPDATE ON Libros


DECLARE UDDATE Estadisticas SET .

BEGIN
---------------------END UpdateEstadisticasGenero;

Triggers INSTEAD OF Slo sobre VISTAS


EMPLEADO DEPARTAMENTO

DNI 11111111 -----

NOMBRE Jos Garca ----

DEPARTAMENT O CT-1 ----

NOMBRE Contabilidad - 1 Recursos Humanos

CDIGO CT-1 RRHH

CREATE VIEW EmpleadoDpto as SELECT e.nombre, d.nombre FROM Empleado E, Departamento D WHERE E.Departamento = D.Codigo;

CREATE OR REPLACE TRIGGER InsertEmepleadoDpto INSERT INTO EmpleadoDpato VALUES (Carlos Gmez', Contabilidad-1); INSTEAD OF INSERT ON EmpleadoDpto DECLARE - - -BEGIN INSERT INTO Empleado VALUES INSERT INTO Departamento VALUES

ERROR en lnea 1: ORA-01779: no se puede modificar una columna que se corresponde con una tabla no reservada por clave

END;

Triggers de Sistema Disparados por eventos del Sistema o eventos relacionados con las acciones de los Usuarios Sistema
Arranque y parada: STARTUP, SHUTDOWN Transacciones: COMMIT, ROLLBACK Errores: SERVERERROR

Usuarios
Login / Logoff Sentencias DDL: CREATE, ALTER, DROP

CREATE OR REPLACE TRIGGER LogCreations AFTER CREATE ON SCHEMA BEGIN INSERT INTO LogCreates (user_id, object_type, object_name, object_owner, creation_date) VALUES (USER, ORA_DCIT_OBJ_TYPE, ORA_DICT_OBJ_NAME,ORA_DICT_OBJ_OWNER, SYSDATE) END LogCreations; /

BEFORE/AFTER Triggers: ejemplo

CREATE OR REPLACE TRIGGER GenerarAutorID BEFORE INSERT OR UPDATE ON Autores FOR EACH ROW BEGIN SELECT id_autores INTO :new.ID FROM Tabla_IDs; UPDATE Tabla_IDs SET id_autores = id_autores + 1; END GenerarAutorID; /

INSERT INTO autores (nombre, apellidos) VALUES ('Lolita', 'Lazarus'); INSERT INTO autores (ID, nombre, apellidos) VALUES (-7, 'Zelda', 'Zoom');

Funciones del Cuerpo del Disparador


Inserting, Deleting, Updating
CREATE OR REPLACE TRIGGER ejemplo BEFORE INSERT OR UPDATE OR DELETE ON tabla BEGIN IF DELETING THEN Acciones asociadas al borrado ELSIF INSERTING THEN Acciones asociadas a la insercin ELSIF UPDATING[(COL1)] Acciones asociadas a la modificacin ELSIF UPDATING[(COL2)] Acciones asociadas a la modificacin END IF; END ejemplo; /

Elevar excepciones en el cuerpo del Disparador


RAISE_APPLICATION_ ERROR (nro_error, mensaje); [-20000 y -20999]

CREATE OR REPLACE TRIGGER ejemplo BEFORE DELETE ON tabla FOR EACH ROW BEGIN IF tabla.columna= valor_no_borrable THEN RAISE_APPLICATION_ERROR(-20000, La fila no se puede borrar); END IF; ... END ejemplo;

Declaracin de Variables
CREATE... BEFORE... [FOR EACH ROW ...] DECLARE Declaracin de variables BEGIN

nombre nombre nombre nombre

CONSTANT NUMBER:=valor; TIPO; nombretabla.nombrecolumna%TYPE; nombretabla%ROWTYPE

Activar / Desactivar disparadores


Todos los disparadores asociados a una tabla:
ALTER TABLE nombre_tabla ENABLE ALL TRIGGERS

ALTER TABLE nombre_tabla DISABLE ALL TRIGGERS


(Por defecto, todos estn activados al crearse)

Un disparador especfico:
ALTER TRIGGER nombre_disparador ENABLE
ALTER TRIGGER nombre_disparador DISABLE

Consultar informacin sobre los disparadores


Eliminar un disparador
DROP TRIGGER nombre_disparador;

Ver todos los disparadores y su estado


SELECT TRIGGER_NAME, STATUS FROM USER_TRIGGERS;

Ver el cuerpo de un disparador


SELECT TRIGGER_BODY FROM USER_TRIGGERS WHERE TRIGGER_NAME='nombre_disparador';

Ver la descripcin de un disparador


SELECT DESCRIPTION FROM USER_TRIGGERS WHERE TRIGGER_NAME= 'nombre_disparador';

Ejemplo
CREATE TRIGGER Ejemplo AFTER DELETE ON tabla1 FOR EACH ROW WHEN ((OLD.nombre=pepe) OR (OLD.edad > 35)) BEGIN DELETE FROM tabla2 WHERE tabla2.cod=:OLD.cod; BEGIN
SELECT Trigger_body FROM USER_TRIGGERS WHERE Trigger_name = 'Ejemplo';

TRIGGER_BODY

----------------------------------

END Ejemplo;
/

DELETE FROM tabla2 WHERE tabla2.cod=:OLD.cod;


END Ejemplo;

SELECT Trigger_type, Triggering_event, Table_name FROM USER_TRIGGERS WHERE Trigger_name = 'Ejemplo'; TYPE ---------------AFTER EACH ROW TRIGGERING_STATEMENT -----------------------DELETE TABLE_NAME ---------tabla1

Restricciones: tablas mutantes Tabla mutante (mutating)


tabla que est siendo modificada por una operacin DML tabla que se ver afectada por los efectos de un DELETE CASCADE debido a la integridad referencial (hasta Oracle8i).

Las rdenes del cuerpo de un disparador (de tipo FOR EACH ROW) no pueden
Leer o actualizar una tabla mutante que est en la propia declaracin del disparador MUTATING TABLE ERROR RUNTIME ERROR

Tablas Mutantes: ejemplo


CREATE OR REPLACE TRIGGER trigger_asignaturas

BEFORE INSERT OR UPDATE ON asignaturas


FOR EACH ROW DECLARE

v_total
BEGIN

NUMBER;

v_nombre VARCHAR2(30);

SELECT COUNT(*)INTO v_total FROM asignaturas -- ASIGNATURAS est MUTANDO


WHERE DNI = :NEW.DNI; -- comprueba si el profesor est sobrecargado

IF v_total >= 10 THEN


SELECT nombre||' '||apellidos INTO v_nombre FROM profesores WHERE DNI = :NEW.DNI; RAISE_APPLICATION_ERROR (-20000, El profesor '|| v_nombre||', est sobrecargado'); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20001, Datos de profesor incorrectos'); END;

Tablas Mutantes: ejemplo


UPDATE asignaturas SET DNI = 000000000

WHERE asignaturas_id = BD;

UPDATE section

SELECT COUNT(*)

INTO v_total
FROM asignaturas WHERE DNI = :NEW.DNI;

*
ERROR at line 1:

ORA-04091: table BD_XX.ASIGNATURAS is mutating, trigger/function may not see it


ORA-06512: at "BD_XX.TRIGGER_ASIGNATURAS", line 5 ORA-04088: error during execution of trigger 'BD_XX.TRIGGER_ASIGNATURAS'

Tablas Mutantes: solucin


Crear 2 disparadores En el disparador a nivel de fila (for each row) almacenamos los datos que queremos consultar (los que provocan el error de tabla mutante) En el disparador a nivel de orden (statement) realizamos la consulta (usando los datos almacenados) La mejor forma de almacenar los valores es utilizar un paquete (opcionalmente, podramos utilizar una tabla)

Tablas Mutantes: solucin


En el trigger a nivel de fila guardaremos el DNI y el nombre del profesor Necesitamos 2 variables globales para que esos datos estn disponibles ms adelante, al ejecutar el trigger a nivel de fila Por lo tanto, creamos un paquete que contendr esas dos variables
CREATE OR REPLACE PACKAGE pck_profesores AS

v_DNI_profesor profesor.DNI%TYPE;
v_nombre_profesor varchar2(50);

END;

Tablas Mutantes: solucin


En el cuerpo del trigger a nivel de fila usamos las variables del paquete para guardar el DNI y el nombre del profesor
CREATE OR REPLACE TRIGGER trigger_asignaturas
BEFORE INSERT OR UPDATE ON asignaturas FOR EACH ROW

BEGIN
IF :NEW.DNI IS NOT NULL THEN BEGIN

pck_profesores.v_DNI_profesor := :NEW.DNI;
SELECT nombre||' '||apellidos INTO pck_profesores.v_nombre_profesor FROM profesores WHERE DNI = pck_profesores.DNI;

EXCEPTION
WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20001, Datos de Profesor erroneos'); END; END IF; END;

Tablas Mutantes: solucin


TRIGGER a nivel de sentencia
Ahora realizamos la consulta utilizando las variables globales
CREATE OR REPLACE TRIGGER trigger_asignaturas_statement
AFTER INSERT OR UPDATE ON asignaturas DECLARE v_total INTEGER; BEGIN

SELECT COUNT(*) INTO v_total


FROM asignaturas

WHERE DNI = pck_profesores.v_DNI_profesor;


-- comprobamos si el profesor aludido est sobrecargado IF v_total >= 10 THEN RAISE_APPLICATION_ERROR (-20000, 'El profesor, '|| pck_profesores.v_nombre_profesor || ', est sobrecargado');

END IF;
END;

Tablas Mutantes: solucin


UPDATE asignaturas
SET DNI = 000000000 WHERE asignaturas_id = BD;

UPDATE asignaturas *

ERROR at line 1: ORA-20000: El profesor Carlos Romero est sobrecargado ORA-06512: at "BD_XX.TRIGGER_ASIGNATURAS_STATEMENT", line 11 ORA-04088: error during execution of trigger 'BD_XX.TRIGGER_ASIGNATURAS_STATEMENT'

TRANSACCIONES y TRIGGERS
Los cambios hechos en un TRIGGER deben ser comprometidos o deshechos con la transaccin en la que se ejecutan
SQL> CREATE TABLE tab1 (col1 NUMBER); Tabla creada.

SQL> CREATE TABLE log (timestamp DATE, operacion VARCHAR2(2000));


Tabla creada.

SQL> INSERT INTO tab1 VALUES (1); INSERT INTO tab1 VALUES (1) * ERROR at line 1:

SQL> CREATE TRIGGER tab1_trig 2 AFTER insert ON tab1

ORA-04092: cannot COMMIT in a trigger ORA-06512: at BD_XX.TAB1_TRIG", line 3 ORA-04088: error during execution of trigger BD_XX.TAB1_TRIG'

3
4 5 6 7

BEGIN
INSERT INTO log VALUES (SYSDATE, 'Insert en TAB1'); COMMIT; END; /

Trigger created.

TRANSACCIONES y TRIGGERS
Se pueden utilizar autonomous transactions de manera que el TRIGGER se ejecute en su propia transaccin
SQL> CREATE OR REPLACE TRIGGER tab1_trig 2 3 4 5 AFTER insert ON tab1 DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN

6
7 8 9

INSERT INTO log VALUES (SYSDATE, 'Insert on TAB1');


COMMIT; END; /

Trigger created.

SQL> INSERT INTO tab1 VALUES (1);

1 row created.

TRANSACCIONES AUTNOMAS
Se pueden utilizar autonomous transactions de manera que el TRIGGER se ejecute en su propia transaccin
CREATE OR REPLACE PROCEDURE Grabar_Log(descripcion VARCHAR2) IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO LOG_APLICACION (CO_ERROR, DESCRIPICION, FX_ERROR) VALUES (SQ_ERROR.NEXTVAL, descripcion, SYSDATE); COMMIT; -- Este commit solo afecta a la transaccion autonoma END ; -- utilizamos el procedimiento desde un bloque PL/SQL DECLARE producto PRECIOS%TYPE; BEGIN producto := '100599'; INSERT INTO PRECIOS (CO_PRODUCTO, PRECIO, FX_ALTA) VALUES (producto, 150, SYSDATE); COMMIT; EXCEPTION WHEN OTHERS THEN Grabar_Log(SQLERRM); ROLLBACK; -- Los datos grabados por "Grabar_Log" se escriben en la base de datos a pesar del -- ROLLBACK, ya que el procedimiento est marcado como transaccin autonoma.

END;

Ejemplos Dada la siguiente relacin:


SOCIO (num_soc, nombre, direccion, telefono)

Se desea mantener la informacin de los socios aunque estos se den de baja, para lo que se crea una tabla SOCIO_BAJA, que contiene los datos de socio y la fecha de baja y que se actualizar cada vez que se borre un socio
SOCIO_BAJA (num_soc, nombre, direccion, telefono, fecha_baja)

Ejemplos Dadas las siguientes relaciones:


PRODUCTO (cod_prod, descripcin, proveedor, unid_vendidas) ALMACEN (cod_prod_s, stock, stock_min, stock_max)
1. 2.

3.

Se desea mantener actualizado el stock del ALMACEN cada vez que se vendan unidades de un determinado producto Cuando el stock est por debajo del mnimo lanzar un mensaje de peticin de compra. Se indicar el nmero de unidades a comprar, segn el stock actual y el stock maximo Si el stock es menor que el mnimo stock permitido, impedir la venta

Ejemplos
Dadas las siguientes relaciones:
PROFESOR (cod_prof) CLASE (cod_clase, cod_prof)

Se define la siguiente vista:


CREATE VIEW informe_profesores AS SELECT p.cod_prof, COUNT(c.cod_clase) total_clases FROM profesor p, clase c WHERE p.cod_prof = c.cod_prof (+) GROUP BY p.cod_prof;

Se desea poder invocar sentencias del tipo:


DELETE FROM informe_profesores WHERE cod_prof = 109;

Disparadores en ORACLE

Bibliografa Oracle Database Concepts - 10g Release 2 (10.2) (Octubre 2005) Oracle Database Application Developer's Guide Fundamentals 10g Release 2 (10.2) (Noviembre 2005) scar Daz Universidad del Pas Vasco (UPV) Bases de Datos Activas

You might also like