Академический Документы
Профессиональный Документы
Культура Документы
PL / SQL
Bloques PL/SQL
Un bloque PL/SQL es la unidad bsica de todo programa. Todos los programas PL/SQL estn compuestos por bloques, los cuales pueden ser secuenciales o anidados.
Bloques annimos Se construyen generalmente de manera dinmica y slo se ejecutan una vez.
Bloques con nombre Son como los bloques annimos, pero tienen una etiqueta que le da al bloque un nombre.
Subprogramas Son procedimientos, funciones y paquetes que son almacenados en base de datos y se ejecutan cuando son invocados.
Disparadores (Triggers) Son bloques con nombre que son almacenados en la base de datos. Son ejecutados implcitamente cuando cierto evento ocurre.
Pgina 2
Procedimientos
Un procedimiento es un bloque PL/SQL al que se le asigna un nombre. Un procedimiento se crea para que realice una determinada tarea de gestin. Los procedimientos son compilados y almacenados en la base de datos. Gracias a ellos se consigue una reutilizacin eficiente del cdigo, ya que se puede invocar al procedimiento las veces que haga falta desde otro cdigo o desde una herramienta de desarrollo como Oracle Developer. Una vez almacenados pueden ser modificados de nuevo.
Crear procedimientos
CREATE [OR REPLACE] PROCEDURE <NOMBRE_PROCEDIMIENTO> [ ( <PARAMETRO_1> [IN | OUT | IN OUT] <TIPO_1> , . <PARAMETRO_N> [IN | OUT | IN OUT] <TIPO_N>) ] <CUERPO_PROCEDIMIENTO> IS
La opcin REPLACE hace que si ya existe un procedimiento con ese nombre, se reemplaza el anterior con el que se crea ahora. Los parmetros son la lista de variables que necesita el procedimiento para realizar su tarea; se indica el tipo de los mismos, pero no su tamao (VARCHAR2 y no VARCHAR2(50)). En los parmetros, el modo pueden ser las palabras IN, OUT o IN OUT. La palabra DECLARE no se utiliza, la seccin de declaraciones figura tras las palabras IS o AS. <CUERPO_PROCEDIMIENTO> es un bloque PL/SQL que contiene el cdigo para el procedimiento.
Pgina 3
Borrar procedimientos
El comando DROP PROCEDURE elimina el procedimiento indicado. DROP PROCEDURE <NOMBRE_PROCEDIMIENTO>
Pgina 4
Funciones
Las funciones son similares a los procedimientos. La diferencia es que las funciones al menos deben de regresar un valor.
Crear funciones
CREATE [OR REPLACE] FUNCTION <NOMBRE_FUNCION> [ ( <PARAMETRO_1> [IN | OUT | IN OUT] <TIPO_1> , . <PARAMETRO_N> [IN | OUT | IN OUT] <TIPO_N>) ] RETURN <TIPO_RETORNO> IS <CUERPO_FUNCION>
Donde <CUERPO_FUNCION> es un bloque PL/SQL que contiene el cdigo para la funcin, y dentro de ste debe estar la instruccin RETURN. Toda funcin ha de devolver un valor, lo cual implica utilizar la instruccin RETURN seguida del valor que se devuelve.
CREATE OR REPLACE FUNCTION MULTIPLICAR(N1 NUMBER,N2 NUMBER ) RETURN NUMBER IS TOT NUMBER; BEGIN TOT:= N1 * N2; RETURN TOT; END; /
La llamada a una funcin debe de ser parte de una instruccin SQL. As, una manera de ejecutar la funcin MULTIPLICAR podra ser:
SELECT MULTIPLICAR(3,5) FROM DUAL;
Pgina 5
SELECT PRECIO_VENTA_ART "PRECIO 2007", MULTIPLICAR(PRECIO_VENTA_ART ,1.05) "PRECIO 2008" FROM TARTICULO;
DECLARE PRECIO_UNITARIO NUMBER :=25 ; UNIDADES NUMBER :=8 ; BEGIN VISUALIZAR(MULTIPLICAR(PRECIO_UNITARIO,UNIDADES)) ; END;
DESC MULTIPLICAR;
Borrar funciones
El comando DROP FUNCTION elimina la funcin indicada. DROP FUNCTION <NOMBRE_FUNCION>
Pgina 6
MODOS DE LOS
PARMETROS
IN - El valor del parmetro real se pasa al procedimiento cuando se produce la llamada al mismo. Dentro del procedimiento, el parmetro formal se comporta como una constante (Solo lectura). Cuando el procedimiento finaliza y devuelve el control al entorno en el que se produjo la llamada, el parmetro real no se modifica.
OUT - Se ignora cualquier valor que el parmetro real pueda tener cuando se produzca la llamada al procedimiento. Dentro del procedimiento, el parmetro formal se comporta como una variable sin inicializar, por lo que contiene el valor NULL. Puede leerse dicha variable y en escribirse en ella. Cuando el procedimiento finaliza y devuelve el control al entorno en el que se produjo la llamada, se asigna el valor del parmetro formal al parmetro real.
IN OUT - Este mtodo es una combinacin de los modos IN y OUT. El valor del parmetro real se pasa al procedimiento cuando se produce la llamada. Dentro del procedimiento, el parmetro formal se comporta como una variable inicializada, pudindose leer y escribir en ella. Cuando el procedimiento finaliza y devuelve el control al entorno en el que se produjo la llamada, los contenidos del parmetro formal se asignan al parmetro real.
-- Este procedimiento ilustra diferentes modos de parmetros y asignaciones de parmetros CREATE OR REPLACE PROCEDURE TEST ( p_In IN NUMBER, p_Out OUT NUMBER, p_InOut IN OUT NUMBER) IS v_LocalVariable NUMBER := 0; BEGIN DBMS_OUTPUT.PUT_LINE('AL PRINCIPIO DE Test:'); IF (p_In IS NULL) THEN DBMS_OUTPUT.PUT('p_In is NULL'); ELSE DBMS_OUTPUT.PUT('p_In = ' || p_In); END IF; IF (p_Out IS NULL) THEN DBMS_OUTPUT.PUT(' p_Out is NULL'); ELSE DBMS_OUTPUT.PUT(' p_Out = ' || p_Out); END IF; IF (p_InOut IS NULL) THEN DBMS_OUTPUT.PUT_LINE(' p_InOut is NULL'); ELSE DBMS_OUTPUT.PUT_LINE(' p_InOut = ' || p_InOut); END IF;
Pgina 7
/* Asignacin de p_In a v_LocalVariable. Esto est, permitido, ya que se lee de un parmetro con modo IN y no se escribe en el mismo. */ v_LocalVariable := p_In; -- Legal /* Asignacin de 7 a p_In. Esto NO EST PERMITIDO, ya que se estara escribiendo en un parmetro con modo IN. */ -- p_In := 7; -- Ilegal /* Asignacin de 7 a p_Out. Esto est permitido, ya que se est escribiendo en un parmetro con modo OUT. */ p_Out := 7; -- Legal /* Asignacin de p_Out a v_LocalVariable. En versiones anteriores a la 7.3, no est permitida la lectura de parmetros con modo OUT. */ v_LocalVariable := p_Out; -- Posiblemente ilegal /* Asignacin de p_InOutParameter a v_LocalVariable. Esto est permitido, ya que se lee de un parmetro con modo IN OUT. */ v_LocalVariable := p_InOut; -- Legal /* Asignacin de 8 a p_InOutParameter. Esto est permitido, ya que se escribe en un parmetro con modo IN OUT. */ p_InOut := 8; -- Legal DBMS_OUTPUT.PUT_LINE('AL FINAL DE Test:'); IF (p_In IS NULL) THEN DBMS_OUTPUT.PUT('p_In is NULL'); ELSE DBMS_OUTPUT.PUT('p_In = ' || p_In); END IF; IF (p_Out IS NULL) THEN DBMS_OUTPUT.PUT(' p_Out is NULL'); ELSE DBMS_OUTPUT.PUT(' p_Out = ' || p_Out); END IF; IF (p_InOut IS NULL) THEN DBMS_OUTPUT.PUT_LINE(' p_InOut is NULL'); ELSE DBMS_OUTPUT.PUT_LINE(' p_InOut = ' || p_InOut); END IF; END Test; / -- Este bloque llama a Test. DECLARE v_In NUMBER := 1; v_Out NUMBER := 2; v_InOut NUMBER := 3; BEGIN DBMS_OUTPUT.PUT_LINE('ANTES DE LLAMAR A TEST:'); DBMS_OUTPUT.PUT_LINE('v_In = ' || v_In ||' v_Out = ' || v_Out ||' v_InOut = ' || v_InOut); Test(v_In, v_Out, v_InOut); DBMS_OUTPUT.PUT_LINE('DESPUES DE LLAMAR A TEST:'); DBMS_OUTPUT.PUT_LINE(' v_In = ' || v_In ||' v_Out = ' || v_Out ||' v_InOut = ' || v_InOut); END; /
Pgina 8
Funcin FACTORIAL La siguiente funcin, calcula el valor factorial a partir de un nmero recibido.
CREATE OR REPLACE FUNCTION FACTORIAL(N IN NUMBER) RETURN NUMBER IS BEGIN IF N<0 THEN RETURN NULL; END IF; IF N=0 OR N=1 THEN RETURN 1; ELSE RETURN N*FACTORIAL(N-1); END IF; END;
Funcin PRECIOMEDIO La siguiente funcin, calcula la media aritmtica del precio de venta de los artculos (PRECIO_VENTA_ART), a partir de los datos de la tabla de artculos(TARTICULO).
CREATE OR REPLACE FUNCTION PRECIOMEDIO RETURN NUMBER IS V_PRECIO NUMBER(11,4); BEGIN SELECT AVG(PRECIO_VENTA_ART) INTO V_PRECIO FROM TARTICULO; RETURN V_PRECIO; END; /
SELECT NOMBRE_ART, PRECIO_VENTA_ART, STOCK_ART FROM TARTICULO WHERE PRECIO_VENTA_ART > PRECIOMEDIO;
Pgina 9
Debido al funcionamiento de los modos de parmetros, todo parmetro real que se corresponda con un parmetro OUT o IN OUT debe ser una variable, y no podr ser una constante o una expresin. Debe de existir una ubicacin para almacenar el valor que se devuelve.
CREATE OR REPLACE PROCEDURE TEST1 ( p_Out OUT NUMBER ) IS v_LocalVariable NUMBER := 5; BEGIN p_Out := v_LocalVariable; END; /
Pgina 10
CREATE OR REPLACE PROCEDURE Parametros ( p_Parameter1 IN OUT VARCHAR2(40), p_Parameter2 IN OUT NUMBER(3,1)) AS BEGIN p_Parameter1 := 'abcdefghijklm'; p_Parameter2 := 12.3; END Parametros;
Por otro lado, se puede generar un error al llamar al procedimiento, si el parmetro real tiene una restriccin de longitud menor, que los valores asignados al parmetro formal.
DECLARE v_Parameter1 VARCHAR2(5):= 'abc'; v_Parameter2 NUMBER(1) :=2; BEGIN parametros(v_Parameter1 , v_Parameter2 ); END ;
ERROR : buffer de cadenas de caracteres demasiado pequeo numrico o de valor ERROR : precisin de nmero demasiado grande numrico o de valor
Pgina 11
CREATE OR REPLACE PROCEDURE Parametros ( p_Parameter1 IN OUT VARCHAR2, p_Parameter2 IN OUT TARTICULO.CODIGO_CAT_ART%TYPE) AS BEGIN p_Parameter2 := 123; END Parametros;
Segn el ejemplo de PROCEDURE Parametros, p_Parameter2 tiene la restriccin de la columna TARTICULO.CODIGO_CAT_ART, que est de finida como NUMBER(3), por lo cual la siguiente llamada al procedimiento Parametros generar un error.
DECLARE v_Parameter1 VARCHAR2(5):= 'abc'; v_Parameter2 NUMBER(5) :=12345; BEGIN parametros(v_Parameter1 , v_Parameter2 ); END ;
Pgina 12
CREATE OR REPLACE PROCEDURE RaiseError ( p_Raise IN BOOLEAN, p_ParameterA OUT NUMBER) AS BEGIN p_ParameterA := 7; IF p_Raise THEN RAISE DUP_VAL_ON_INDEX; END IF; END RaiseError;
DECLARE v_TempVar NUMBER := 1; BEGIN DBMS_OUTPUT.PUT_LINE('Valor inicial: ' || v_TempVar); RaiseError(FALSE, v_TempVar); DBMS_OUTPUT.PUT_LINE('Valor despus de la 1 llamada: ' || v_TempVar); v_TempVar := 2; DBMS_OUTPUT.PUT_LINE('Valor antes de la 2 llamada: ' || v_TempVar); RaiseError(TRUE, v_TempVar); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Valor despus de la 2 llamada: ' || v_TempVar); END;
Pgina 13
UTILIZACIN DE NOCOPY
A partir de Oracle 8i se incluye la indicacin de compilacin NOCOPY, la sintaxis para utilizar dicha indicacin a la hora de declarar un parmetro es la siguiente
Si NOCOPY est especificado, el compilador PL/SQL intenta pasar el parmetro por referencia, en lugar de por valor.
CREATE OR REPLACE PROCEDURE NoCopyTest ( p_InParametro IN NUMBER, p_OutParametro OUT NOCOPY VARCHAR2, p_InOutParametro IN OUT NOCOPY CHAR) IS BEGIN NULL; END NoCopyTest;
La utilizacin de NOCOPY con un parmetro de modo IN da error de compilacin. Cuando pasamos un parmetro por referencia, cualquier modificacin del parmetro formal tambin modifica el parmetro real, ya que ambos apuntan al mismo lugar. Esto significa que, si se produce una excepcin despus de haber modificado el parmetro formal, el valor original del parmetro real se habr perdido.
Pgina 14
CREATE OR REPLACE PROCEDURE RaiseError ( p_Raise IN BOOLEAN, p_ParameterA OUT NOCOPY NUMBER) AS BEGIN p_ParameterA := 7; IF p_Raise THEN RAISE DUP_VAL_ON_INDEX; ELSE RETURN; END IF; END RaiseError; /
DECLARE v_TempVar NUMBER := 1; BEGIN DBMS_OUTPUT.PUT_LINE('Valor inicial: ' || v_TempVar); RaiseError(FALSE, v_TempVar); DBMS_OUTPUT.PUT_LINE('Valor despus de la 1 llamada: ' || v_TempVar); v_TempVar := 2; DBMS_OUTPUT.PUT_LINE('Valor antes de la 2 llamada: ' || v_TempVar); RaiseError(TRUE, v_TempVar); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Valor despus de la 2 llamada: ' || v_TempVar); END;
Pgina 15
CREATE OR REPLACE PROCEDURE nominal( p_ParametroA VARCHAR2, p_ParametroB NUMBER, p_ParametroC BOOLEAN, p_ParametroD DATE) AS BEGIN NULL; END nominal;
DECLARE v_Variable1 VARCHAR2(10); v_Variable2 NUMBER(7,6); v_Variable3 BOOLEAN; v_Variable4 DATE; BEGIN nominal(p_ParametroA => v_Variable1, p_ParametroB => v_Variable2, p_ParametroC => v_Variable3, p_ParametroD => v_Variable4); END;
Las notaciones nominal y posicional pueden utilizarse conjuntamente en la misma llamada, en tal caso, los primeros argumentos a especificar deben ser por posicin.
DECLARE v_Variable1 VARCHAR2(10); v_Variable2 NUMBER(7,6); v_Variable3 BOOLEAN; v_Variable4 DATE; BEGIN nominal(v_Variable1, v_Variable2, p_ParametroC => v_Variable3, p_ParametroD => v_Variable4); END;
Pgina 16
Al igual que las declaraciones de las variables, los parmetros formales pueden tener valores predeterminados. Si un determinado parmetro tiene un valor por defecto, no es obligatorio pasarlo desde la llamada. Si se pasa valor, el valor del parmetro real sustituir al predeterminado. La sintaxis a utilizar:
CREATE OR REPLACE PROCEDURE DefaultTest ( p_ParametroA NUMBER DEFAULT 10, p_ParametroB VARCHAR2 DEFAULT 'abcdef', p_ParametroC DATE DEFAULT SYSDATE) AS BEGIN DBMS_OUTPUT.PUT_LINE('A: '|| p_ParametroA ||' B: ' || p_ParametroB ||' C:' || TO_CHAR(p_ParametroC,'DD-MM-YYYY')); END DefaultTest;
BEGIN -- Usa el valor predeterminado tanto para p_ParametroB -- como para p_ParametroC. DefaultTest(20); END;
Pgina 17
PAQUETES
Un paquete es una estructura de PL/SQL que permite almacenar juntos varios objetos relacionados entre s. Un paquete tiene dos partes separadas: la especificacin y el cuerpo. Cada una de ellas se almacena independientemente en el diccionario de datos. Un paquete es fundamentalmente una seccin declarativa. Cualquier cdigo que pueda incluirse en la parte declarativa de un bloque puede incluirse en un paquete, incluidos procedimientos, funciones, cursores y variables. Los paquetes no pueden ser llamados o pasados como parmetros. La especificacin del paquete incluye informacin acerca del contenido del paquete. Sin embargo no contiene cdigo para ninguno de los procedimientos.
CREATE [ OR REPLACE ] PACKAGE <NOMBRE_PAQUETE> IS -- Especificaciones de procedimientos -- Especificaciones de funciones -- Declaraciones de variables -- Declaraciones de excepciones -- Declaraciones de cursores END [<NOMBRE_PAQUETE>];
El cuerpo del paquete es un objeto independiente de la cabecera del paquete en el diccionario de datos. El cuerpo del paquete no puede compilarse hasta que la cabecera del paquete se haya compilado correctamente. El cuerpo contiene el cdigo correspondiente a las declaraciones formales de los subprogramas que aparecen en la cabecera del paquete.
CREATE [ OR REPLACE ] PACKAGE BODY <NOMBRE_PAQUETE> IS -- Declaraciones de los subprogramas END [<NOMBRE_PAQUETE>];
Cualquier objeto que se declare en la cabecera del paquete, se encuentra dentro de mbito y es visible desde fuera del paquete, siempre que el objeto se distinga precedindole con el nombre del paquete donde se encuentra definido.
Pgina 18
Pgina 19
Pgina 20
TRIGGER
TIPOS DE DISPARADORES
Los disparadores son parecidos a los procedimientos y funciones, en el sentido de que son bloques de PL/SQL con secciones declarativa, ejecutable y de tratamiento de excepciones. Los disparadores deben almacenarse en la base de datos como objetos independientes y no pueden ser locales a un bloque o paquete. Un TRIGGER difiere en gran medida de un procedimiento almacenado en la B.D. ya que unos son ejecutados de manera explcita por el usuario, una aplicacin o un TRIGGER y los otros son ejecutados de manera implcita por Oracle ante la ocurrencia de algn evento. El suceso que lo activa puede ser una operacin DML (INSERT, UPDATE o DELETE) sobre una tabla e incluso en algunas ocasiones sobre una vista. Existen tres tipos de disparadores: DML, de sustitucin y del sistema. Los disparadores son ampliamente empleados en la personalizacin de la Administracin de la B.D. por ejemplo: un TRIGGER puede restringir las operaciones DML sobre una tabla en particular en ciertas horas del da, durante una o varias semanas o incluso meses. Otras aplicaciones de los TRIGGERS pueden ser las siguientes: generacin automtica de valores derivados de una columna, prevenir transacciones invlidas, proporcionar auditorias sofisticadas, generar estadsticas de acceso, publicar informacin de los eventos generados por la B.D., las actividades de los usuarios o de las estructuras SQL que se ha ejecutado.
CREACIN DE DISPARADORES
CREATE [OR REPLACE] TRIGGER <NOMBRE_DISPARADOR> BEFORE | AFTER | INSTEAD OF DELETE | INSERT | UPDATE [OF <NOMBRE_COLUMNA> ] ON <NOMBRE_TABLA> [ FOR EACH ROW ] [ WHEN <CONDICIN> ] { <BLOQUE PL/SQL> }
END [<NOMBRE_DISPARADOR>] ;
Pgina 21
DISPARADORES DML
Los disparadores DML se activan a partir de instrucciones DML y el tipo de instruccin determina el tipo de disparador. Estos pueden definirse para las instrucciones INSERT, DELETE y/o UPDATE y podrn dispararse antes o despus de la operacin. Dichos disparadores pueden dispararse en operaciones de fila o de instruccin. Las combinaciones de estos factores determinan el tipo de disparador (un total de 12). Un disparador puede tambin dispararse para ms de un tipo de instruccin DML sobre una tabla. El cdigo de disparador se ejecutar junto con la propia instruccin de disparo, como parte de la misma transaccin. Una tabla puede tener cualquier nmero de disparadores definido sobre la misma, incluyendo ms de un disparador DML del mismo tipo. Por ejemplo, pueden definirse dos disparadores posteriores a la insercin y de nivel de fila. Todos los disparadores del mismo tipo se activarn de forma secuencial. Por defecto el disparador se ejecuta por instruccin, si se desea que se ejecute por cada fila que afecte la instruccin, tenemos que especificar la clusula FOR EACH ROW. Si deseamos que el disparador se lance cuando afecte a una determinada columna, debemos indicarlo mediante la sintaxis OF <NOMBRE_COLUMNA_1> [ , <NOMBRE_COLUMNA_2>...]
Ejemplos: CREATE TRIGGER CAMBIO_CATEGORIA BEFORE DELETE OR INSERT OR UPDATE ON TCATEGORIA <BLOQUE PL/SQL> . . .. .. END CAMBIO_CATEGORIA;
Pgina 22
CREATE TRIGGER CHEQUEAR_ART BEFORE INSERT OR UPDATE OF PRECIO_VENTA_ART, PESO_ART ON TARTICULO FOR EACH ROW WHEN (:NEW.CODIGO_CAT_ART = '101') <BLOQUE PL/SQL> . . .. .. END CHEQUEAR_ART;
CREATE TRIGGER CHEQUEAR_ART BEFORE INSERT OR UPDATE OF PRECIO_VENTA_ART, PESO_ART ON TARTICULO FOR EACH ROW WHEN (NEW.CODIGO_CAT_ART = '101') PROCEDIMIENTO_ART (:NEW.CODIGO_ART, :NEW.PESO_ART); END CHEQUEAR_ART;
Pgina 23
1 Ejecucin de los disparadores previos de nivel de instruccin. 2 Para cada fila aceptada por la instruccin: 2.A Ejecucin de los disparadores previos de nivel de fila. 2.B Ejecucin de la propia instruccin. 2.C Ejecucin de los disparadores posteriores de nivel de fila. 3 Ejecucin de los disparadores posteriores de nivel de instruccin.
Tabla
CREATE TABLE temp_table ( num_col NUMBER(3), char_col VARCHAR2(50) ) ;
Pgina 24
Paquete
CREATE OR REPLACE PACKAGE TrigPackage AS -- Contador global que se usa en los disparadores v_Contador NUMBER; END TrigPackage;
Disparadores
CREATE OR REPLACE TRIGGER BINSTRUCCION BEFORE UPDATE ON TProveedores BEGIN -- Puesta a cero del contador. TrigPackage.v_Contador := 0; INSERT INTO temp_table (num_col, char_col) VALUES (trig_seq.NEXTVAL,'Before INSTRUCCION: Contador = ' || TrigPackage.v_Contador); -- Incremento del contador para el prximo disparador. TrigPackage.v_Contador := TrigPackage.v_Contador + 1; END BINSTRUCCION; /
CREATE OR REPLACE TRIGGER AINSTRUCCION1 AFTER UPDATE ON TProveedores BEGIN INSERT INTO temp_table (num_col, char_col) VALUES (trig_seq.NEXTVAL,'After INSTRUCCION 1: Contador = ' || TrigPackage.v_Contador); -- Incremento del contador para el prximo disparador. TrigPackage.v_Contador := TrigPackage.v_Contador + 1; END AINSTRUCCION1; /
CREATE OR REPLACE TRIGGER AINSTRUCCION2 AFTER UPDATE ON TProveedores BEGIN INSERT INTO temp_table (num_col, char_col) VALUES (trig_seq.NEXTVAL, 'After INSTRUCCION 2: Contador = ' ||TrigPackage.v_Contador); -- Incremento del contador para el prximo disparador. TrigPackage.v_Contador := TrigPackage.v_Contador + 1; END AINSTRUCCION2; /
CREATE OR REPLACE TRIGGER BFILA1 BEFORE UPDATE ON TProveedores FOR EACH ROW BEGIN INSERT INTO temp_table (num_col, char_col) VALUES (trig_seq.NEXTVAL, 'Before FILA 1: Contador = ' || TrigPackage.v_Contador); -- Incremento del contador para el prximo disparador. TrigPackage.v_Contador := TrigPackage.v_Contador + 1; END BFILA1; /
Pgina 25
Disparadores
(Cont.)
CREATE OR REPLACE TRIGGER BFILA2 BEFORE UPDATE ON TProveedores FOR EACH ROW BEGIN INSERT INTO temp_table (num_col, char_col) VALUES (trig_seq.NEXTVAL, 'Before FILA 2: Contador = ' || TrigPackage.v_Contador); -- Incremento del contador para el prximo disparador. TrigPackage.v_Contador := TrigPackage.v_Contador + 1; END BFILA2; /
CREATE OR REPLACE TRIGGER BFILA3 BEFORE UPDATE ON TProveedores FOR EACH ROW BEGIN INSERT INTO temp_table (num_col, char_col) VALUES (trig_seq.NEXTVAL, 'Before FILA 3: Contador = ' || TrigPackage.v_Contador); -- Incremento del contador para el prximo disparador. TrigPackage.v_Contador := TrigPackage.v_Contador + 1; END BFILA3; /
CREATE OR REPLACE TRIGGER AFILA AFTER UPDATE ON TProveedores FOR EACH ROW BEGIN INSERT INTO temp_table (num_col, char_col) VALUES (trig_seq.NEXTVAL, 'After FILA: Contador = ' || TrigPackage.v_Contador); -- Incremento del contador para el prximo disparador. TrigPackage.v_Contador := TrigPackage.v_Contador + 1; END AFILA; /
Pgina 26
UPDATE TProveedores SET poblacion_pr = 'LEGANS' WHERE cod_pr IN ('PCC', 'ASU'); SELECT * FROM temp_table ORDER BY num_col;
Pgina 27
Tabla
SELECT * FROM TCATEGORIA ORDER BY CODIGO_CAT ;
Disparador
CREATE OR REPLACE TRIGGER COD_CAT_NUEVO BEFORE INSERT ON TCATEGORIA FOR EACH ROW BEGIN SELECT CODIGO_CAT.NEXTVAL INTO :NEW.CODIGO_CAT END COD_CAT_NUEVO;
FROM DUAL;
Pgina 28
Sentencia activadora
INSERT INTO TCATEGORIA (NOMBRE_CAT ) VALUES ('IMPRESORAS');
Resultado
SELECT * FROM TCATEGORIA ORDER BY CODIGO_CAT ;
Un disparador de nivel de fila se activa una vez por cada fila que procese la instruccin de disparo. Dentro del disparador, es posible acceder a los datos de la fila que se est procesando. Esto es posible mediante dos identificadores de correlacin :new y :old. El carcter dos puntos que les precede, indica que son variables de acoplamiento. La sintaxis :new.nombre_campo, es vlida nicamente si nombre_campo es un campo de la tabla disparo. El identificador :old tendr los valores originales antes del borrado, o de la modificacin y NULL para el proceso de insercin. El identificador :new tendr los valores nuevos de la modificacin, o de la insercin y NULL para el proceso de borrado.
Pgina 29
CLUSULA REFERENCING
Si deseamos dar un nombre diferente para los identificadores de correlacin :new y :old, podemos utilizar la clusula referencing. Dicha clusula se incluye despus del suceso de disparo y antes de la clusula when y for each row .
En el cuerpo del disparador se podr utilizar :nombre_old y :nombre_new en lugar de :old y :new. En la clusula referencing los identificadores se escriben sin los dos puntos.
Sentencia activadora
INSERT INTO TCATEGORIA (NOMBRE_CAT ) VALUES ('FOTOGRAFA');
Resultado
SELECT * FROM TCATEGORIA ORDER BY CODIGO_CAT ;
Pgina 30
CLUSULA WHEN
La clusula WHEN es nicamente valida en los disparadores de nivel de fila. El cuerpo del disparador, solo se ejecutar sobre aquellas filas que cumplan la condicin especificada.
WHEN <condicin_disparador>
PREDICADOS DE DISPARADORES
Para un disparador que se pueda activar por diferentes acciones producidas ( INSERT, DELETE, UPDATE) , existen tres funciones booleanas que se pueden utilizar para determinar qu operacin ha lanzado el disparador.
BEGIN IF INSERTING THEN <proceso_insertar>; ELSIF UPDATING THEN <proceso_modificar>; ELSE <proceso_borrar>; END IF;
Pgina 31
DISPARADORES DE SUSTITUCIN
A diferencia de los disparadores DML, que actan adems de las operaciones INSERT, UPDATE y DELETE, los disparadores de sustitucin actan en lugar de la orden DML. Los disparadores de sustitucin pueden definirse nicamente sobre vistas, mientras que los disparadores DML se definen sobre tablas.
Existe una clasificacin entre vistas modificables y vistas no modificables. Una vista modificable es aquella que permite una instruccin DML. En general, una vista es modificable si no contiene uniones (INNER JOIN, campos de ms de una tabla), agregaciones (SUM, COUNT), agrupaciones (GROUP BY) ni el operador DISTINCT. Sin embargo algunas vistas que trabajan con ms de una tabla, puede ser modificable si la operacin DML ejecutada solo afecta a columnas de una sola tabla base.
Si una vista no es modificable, es posible escribir un disparador de sustitucin que realice las operaciones deseadas, permitiendo as la modificacin de la misma. Los disparadores de sustitucin, por supuesto, tambin pueden escribirse para vistas modificables.
La clusula FOR EACH ROW es opcional para los disparadores de sustitucin, ya que todos los disparadores de sustitucin son de nivel de fila, independientemente de poner la clusula o no.
Pgina 32
Disparador
CREATE OR REPLACE TRIGGER insert_pedido_prov instead OF INSERT ON PEDIDOS_COMPRA_PROVEEDOR DECLARE v_pr VARCHAR2(15); CURSOR c_prov IS SELECT cif_pr FROM tproveedores WHERE cif_pr = :NEW.cif; FUNCTION buscar_pr RETURN boolean IS v_encontrado boolean := TRUE; BEGIN OPEN c_prov; FETCH c_prov INTO v_pr; v_encontrado := c_proV % FOUND; CLOSE c_proV; RETURN v_encontrado; END buscar_pr; BEGIN IF NOT BUSCAR_PR() THEN INSERT INTO tproveedores(cif_pr, nombre_pr, cod_pr) VALUES(:NEW.cif, :NEW.nombre, :NEW.cod); END IF; INSERT INTO tpedidos_compra(numero_pedido_pc, cif_pc, comercial_pc, forma_pago_pc) VALUES('PC-' || TRIM (' ' FROM TO_CHAR (NUMERO_PEDIDO_PC.NEXTVAL , '000000') ), :NEW.cif, :NEW.comercial, :NEW.fp); END insert_pedido_prov;
Pgina 33
Sentencia activadora
INSERT INTO PEDIDOS_COMPRA_PROVEEDOR (CIF,COD, NOMBRE, PERSONA, COMERCIAL, FP) VALUES ('A-33317884', 'PIO', 'PIONNER', 'JOSE MARIA', 'MARCOS SERRANO', '90');
Resultado
select NUMERO_PEDIDO_PC, CIF_PC, FECHA_PEDIDO_PC, FECHA_ENTRADA_PC, FORMA_PAGO_PC, COMERCIAL_PC, PORTES_PC, OBSERVACIONES_PC from TPEDIDOS_COMPRA;
select CIF_PR, COD_PR, NOMBRE_PR, DIR_PR, POBLACION_PR, PROVINCIA_PR, PAIS_PR, CP_PR,TLF1_PR, FAX_PR, PERSONA_PR from TPROVEEDORES;
Pgina 34
CREATE [OR REPLACE] TRIGGER <NOMBRE_DISPARADOR> BEFORE | AFTER <Lista_sucesos_DDL> |<Lista_sucesos_base_datos> ON DATABASE | [<esquema>.]SCHEMA [ WHEN <clusula> ] { PL/SQL Bloque } . . END [<NOMBRE_DISPARADOR> ] ;
Un disparador del sistema puede definirse en el nivel de base de datos o en el nivel de esquema. Un disparador de nivel de base de datos se activar siempre que ocurra el suceso de disparo, mientras que un disparador de nivel de esquema se activara nicamente cuando ocurra el suceso de disparo en el esquema especificado. Las palabras clave DATABASE y SCHEMA determinan el nivel de un disparador del sistema dado. Si el esquema no se especifica mediante la palabra clave SCHEMA, el valor predeterminado es el esquema propietario del disparador.
Pgina 35
SUCESOS
STARTUP AFTER
SHUTDOWN BEFORE
SERVERERROR AFTER
LOGON AFTER
LOGOFF BEFORE
Pgina 36
Disparador.
CREATE OR REPLACE TRIGGER TRABAJA_APLICACION AFTER DROP OR CREATE OR ALTER ON A01.SCHEMA BEGIN INSERT INTO temp_table VALUES (8, CONCAT('TRABAJA: ' , USER) ); END TRABAJA_APLICACION;
Resultado
SELECT * FROM TEMP_TABLE;
Pgina 37
Disparador.
CREATE OR REPLACE TRIGGER CONECTA_TODOS AFTER LOGON ON DATABASE BEGIN INSERT INTO temp_table VALUES (2,CONCAT( 'CONECTADOS USUARIO ' , USER) ); END CONECTA_TODOS;
Disparador
CREATE OR REPLACE TRIGGER CONECTA_APLICACION AFTER LOGON ON A01.SCHEMA BEGIN INSERT INTO temp_table VALUES (1, CONCAT('CONECTA USUARIO ' , USER) ); END CONECTA_APLICACION;
Resultado
SELECT NUM_COL,CHAR_COL FROM TEMP_TABLE ORDER BY NUM_COL ;
Pgina 38
Dentro de los disparadores del sistema hay varias funciones de atributos de sucesos disponibles. Estas permiten que el cuerpo de un disparador obtenga informacin sobre el suceso de disparo. Las funciones de atributos de sucesos son funciones PL/SQL independientes que pertenecen a SYS. Por omisin, no existen sinnimos definidos para las mismas, por lo que deben ir precedidas de SYS para que puedan resolverse.
Algunas funciones de atributos de sucesos: DICTIONARY_OBJ_TYPE Devuelve un VARCHAR2(20), aplicable a los sucesos CREATE, DROP, ALTER. Devuelve el tipo de objeto de diccionario sobre el que tuvo lugar la operacin DDL que activ el suceso.
DICTIONARY_OBJ_NAME Devuelve un VARCHAR2(30), aplicable a los sucesos CREATE, DROP, ALTER. Devuelve el nombre del objeto de diccionario sobre el que tuvo lugar la operacin DDL que activ el suceso.
DICTIONARY_OBJ_OWNER Devuelve un VARCHAR2(30), aplicable a los sucesos CREATE, DROP, ALTER. Devuelve el propietario del objeto de diccionario sobre el que tuvo lugar la operacin DDL que activ el suceso.
SYSEVENT Devuelve un VARCHAR2(20), aplicable a todos los sucesos. Devuelve el suceso del sistema que activ el disparador.
LOGIN_USER Devuelve un VARCHAR2(30), aplicable a todos los sucesos. Devuelve el identificador del usuario que activ el disparador.
Pgina 39
CREATE TABLE NUEVOS_OBJETOS ( USUARIO VARCHAR2(30), OBJETO VARCHAR2(20), NOMBRE VARCHAR2(30), PROPIETARIO VARCHAR2(30), FECHA DATE);
Disparador.
CREATE OR REPLACE TRIGGER T_NUEVOS_OBJETOS AFTER CREATE ON DATABASE BEGIN INSERT INTO NUEVOS_OBJETOS (USUARIO, OBJETO, NOMBRE, PROPIETARIO, FECHA) VALUES (USER, SYS.DICTIONARY_OBJ_TYPE , SYS.DICTIONARY_OBJ_NAME, SYS.DICTIONARY_OBJ_OWNER , SYSDATE); END T_NUEVOS_OBJETOS;
Resultado
SELECT * FROM NUEVOS_OBJETOS ;
Pgina 40
TABLA MUTANTE
Una tabla mutante es una tabla que se est modificando debido a una instruccin DML. En el caso de un disparador es la tabla a la que se refiere el disparador en la clusula ON. Un disparador no puede leer o modificar una tabla mutante ni tampoco leer o modificar una columna de clave externa relativa a una restriccin de la tabla a la que se refiere el trigger (s se podra utilizar y modificar el resto de columnas). Es decir, no podemos hacer consultas ni instrucciones DML sobre una tabla sobre la que ya se ha comenzado a modificar, insertar o eliminar datos. En realidad slo los triggers de fila no pueden acceder a tablas mutantes. Por ello la solucin al problema suele ser combinar triggers de tabla con triggers de fila (conociendo el orden de ejecucin de los triggers). Normalmente los triggers de fila almacenan los valores que se desean cambiar dentro de una tabla preparada al efecto o dentro de variables de paquete (accesibles desde cualquier trigger si se crea dentro de dicho paquete).
Pgina 41