Disparadores en ORACLE

Disparadores en ORACLE Bibliografía Oracle® Database Concepts - 10g Release 2 (10.2) (Octubre 2005) Oracle® Database Application Developer's Guide –

8 downloads 169 Views 2MB Size

Recommend Stories


Manejando JSON en Oracle Database 12c
Manejando JSON en Oracle Database 12c Por Francisco Riccio Introducción A partir de la versión Oracle Database 12.1.0.2 es posible trabajar con el fo

Funciones, procedimientos, secuencias y cursores en Oracle
Escuela Técnica Superior de Ingeniería Informática Departamento de Lenguajes y Sistemas Informáticos Escuela Técnica Superior de Ingeniería Informáti

Oracle PeopleSoft Financials
Oracle PeopleSoft Financials "Esta versión de PeopleSoft Enterprise Financials ayudará a las empresas operar con mayor eficiencia, ahorrando tiempo y

Oracle Directory Services: Administración
Oracle University | Contacte con nosotros: 902 302 302 Oracle Directory Services: Administración Duración: 5 Días Lo que aprenderá El curso comienza

Migración de Oracle a PostgreSQL
Migración de Oracle a PostgreSQL … Migración de Oracle a PostgreSQL …hacia la independencia tecnológica Prof. José Tomás Cadenas, PhD jtcadenas@usb

Story Transcript

Disparadores en ORACLE

Bibliografía 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 Díaz – Universidad del País Vasco (UPV) Bases de Datos Activas

Introducción PL/SQL: lenguaje de programación estructurado en bloques Bloques: unidad mínima en PL/SQL

DECLARE ▬ optional BEGIN ▬ required EXCEPTION ▬ optional

 Soportan DML y DDL  Anónimos / Con nombre → TRIGGERS

END; /

required

Disparadores (triggers) en Oracle: bloques de código que son implícitamente invocados cuando algo sucede CREATE TRIGGER Triggers VS Procedimientos NombreTrigger  Ejecución Implícita: Disparar  No admiten argumentos

Aplicaciones:  Restricciones (Constraints)  Auditorías  Informar de Eventos

BEFORE INSERT ON StarsIn DECLARE ….. END; TRIGGER / CREATE PROCEDURE Get_emp_rec (Emp_number IN Emp_tab.Empno%TYPE) AS BEGIN - - - - END; /

PROCEDIMIENTO

Introducción

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

Estructura General de un Disparador

Evento

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

[WHEN condición] Granularidad [FOR EACH ROW | STATEMENT]

Condición

BEGIN

cuerpo del trigger END;

Acción

Temporalidad del Evento: AFTER / BEFORE BEFORE  Ejecutan la acción asociada antes de que la sentencia sea ejecutada  Decidir si la acción debe realizarse  Utilizar valores alternativos para la sentencia CREATE TRIGGER NombreTrigger BEFORE Insert ON NombreTabla ….

Los de tipo BEFORE son mejores en términos de rendimiento

AFTER  Ejecutan la acción asociada después 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 acción 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 acción 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 acción asociada, independientemente del número de filas que se vean afectadas por la sentencia CREATE TRIGGER NombreTrigger BEFORE Insert ON NombreTabla [STATEMENT]

 Utilizar cuando la acción 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 auditoría

Condición Expresa una condición que debe cumplirse en el momento de producirse el evento, para que la acción sea ejecutada. WHEN persona.nombre = 'pepe' OR persona.edad > 35

Se puede utilizar cualquier combinación de operadores lógicos (AND, OR, NOT) y relacionales (< >= = ). No se puede especificar una condición 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 Ejecución Una sentencia SQL puede disparar varios TRIGGERS. La activación de un trigger puede disparar la activación de otros triggers. 1. 2.

3.

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)

Se compromete o se deshace toda la transacción El orden de ejecución 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

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; /

Evento Condición

Acción

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 tenía la columna antes del cambio debido a una modificación (UPDATE)  Al valor de una columna antes de una operación de borrado sobre la misma (DELETE)  Al valor NULL para operaciones de inserción (INSERT)

Con NEW.nombre_columna referenciamos:  Al valor de una nueva columna después de una operación de inserción (INSERT)  Al valor de una columna después de modificarla mediante una sentencia de modificación (UPDATE)  Al valor NULL para una operación de borrado (DELETE) SINTAXIS





Condición (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 años, eliminar también dicha persona de la tabla persona2

Persona Cod Nombre Edad C1 C2 C3 C4 C5

María Pepe Pepe Luisa Pepe

25 40 45 48 22

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

Persona2 Cod C1 C2 C3 C4 C5

Nombre Edad María Pepe Pepe Luisa Pepe

25 40 45 48 22

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

María 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 sólo algunas (WHEN) LIBROS

ESTADÍSTICAS

ISBN

GENERO

TÍTULO

GENERO

TOTAL_LIBROS

100-09-89

Novela

El Quijote

Novela

50

-----

----

----

Infantil

15

CREATE OR REPLACE TRIGGER UpdateEstadisticasGenero

AFTER INSERT OR DELETE OR UPDATE ON Libros DECLARE UDDATE Estadisticas SET ….

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

/

Triggers INSTEAD OF Sólo sobre VISTAS EMPLEADO

DNI

DEPARTAMENTO

NOMBRE

DEPARTAMENT O

11111111

José García

CT-1

-----

----

----

NOMBRE

CÓDIGO

Contabilidad - 1

CT-1

Recursos Humanos

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 Gómez', ‘Contabilidad-1’);

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

INSTEAD OF INSERT ON EmpleadoDpto DECLARE - - -BEGIN INSERT INTO Empleado VALUES … INSERT INTO Departamento VALUES …

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 inserción ELSIF UPDATING[(‘COL1’)] Acciones asociadas a la modificación ELSIF UPDATING[(‘COL2’)] Acciones asociadas a la modificación 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;

Declaración de Variables CREATE... BEFORE... [FOR EACH ROW ...] DECLARE Declaración 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 están activados al crearse)

Un disparador específico: ALTER TRIGGER nombre_disparador ENABLE ALTER TRIGGER nombre_disparador DISABLE

Consultar información 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 descripción de un disparador SELECT DESCRIPTION FROM USER_TRIGGERS WHERE TRIGGER_NAME= 'nombre_disparador';

Ejemplo SELECT Trigger_body FROM USER_TRIGGERS

CREATE TRIGGER Ejemplo

WHERE Trigger_name = 'Ejemplo';

AFTER DELETE ON tabla1 FOR EACH ROW

TRIGGER_BODY

WHEN ((OLD.nombre=’pepe’) OR (OLD.edad > 35))

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

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

BEGIN

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

END Ejemplo;

END Ejemplo;

/

/

SELECT Trigger_type, Triggering_event, Table_name FROM USER_TRIGGERS WHERE Trigger_name = 'Ejemplo'; TYPE

TRIGGERING_STATEMENT

TABLE_NAME

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

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

----------

AFTER EACH ROW

DELETE

tabla1

Restricciones: tablas mutantes Tabla mutante (mutating)  tabla que está siendo modificada por una operación 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 declaración 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

NUMBER;

v_nombre VARCHAR2(30); BEGIN

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

* ERROR at line 1:

SELECT COUNT(*)

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

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: solución 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, podríamos utilizar una tabla)

Tablas Mutantes: solución En el trigger a nivel de fila guardaremos el DNI y el nombre del profesor  Necesitamos 2 variables globales para que esos datos estén disponibles más 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: solución  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: solución 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: solución 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 transacción 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

3

AFTER insert ON tab1

BEGIN

4

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

5

COMMIT;

6

END;

7

/

Trigger created.

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'

TRANSACCIONES y TRIGGERS Se pueden utilizar autonomous transactions de manera que el TRIGGER se ejecute en su propia transacción SQL> CREATE OR REPLACE TRIGGER tab1_trig 2 3

AFTER insert ON tab1 DECLARE

4 5

PRAGMA AUTONOMOUS_TRANSACTION; BEGIN

6

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

7

COMMIT;

8

END;

9

/

Trigger created.

SQL> INSERT INTO tab1 VALUES (1);

1 row created.

TRANSACCIONES AUTÓNOMAS Se pueden utilizar autonomous transactions de manera que el TRIGGER se ejecute en su propia transacción 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 transacción autonoma.

END;

Ejemplos Dada la siguiente relación: SOCIO (num_soc, nombre, direccion, telefono)

Se desea mantener la información 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, descripción, 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 mínimo lanzar un mensaje de petición de compra. Se indicará el número de unidades a comprar, según el stock actual y el stock maximo Si el stock es menor que el mínimo 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

Bibliografía 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 Díaz – Universidad del País Vasco (UPV) Bases de Datos Activas

Get in touch

Social

© Copyright 2013 - 2024 MYDOKUMENT.COM - All rights reserved.