View
172
Download
2
Category
Preview:
Citation preview
Resumen PL/SQL III Pgina 1
FEBRERO - 2009
Resumen PL/SQL III Curso Base de Datos
CURSO
BASE DE
DATOS PL / SQL
Resumen PL/SQL III Pgina 2
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.
Los tipos de bloques son:
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.
Resumen PL/SQL III Pgina 3
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
[ ( [IN | OUT | IN OUT] ,
.
[IN | OUT | IN OUT] ) ] 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.
es un bloque PL/SQL que contiene el cdigo para el procedimiento.
Resumen PL/SQL III Pgina 4
CREATE OR REPLACE PROCEDURE SALUDO IS
BEGIN
DBMS_OUTPUT.PUT_LINE('ALMACENES VISIN FUTURA') ;
END;
Para ejecutar este procedimiento desde la lnea de comando se usa la instruccin:
BEGIN SALUDO;
END;
CREATE OR REPLACE PROCEDURE VISUALIZAR(TEXTO IN VARCHAR2) IS
BEGIN
DBMS_OUTPUT.PUT_LINE(TEXTO) ;
END;
/
BEGIN
VISUALIZAR('Empresa de Marketin Promocional');
VISUALIZAR('Logstica propia');
END;
/
Borrar procedimientos
El comando DROP PROCEDURE elimina el procedimiento indicado.
DROP PROCEDURE
Resumen PL/SQL III Pgina 5
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
[ ( [IN | OUT | IN OUT] ,
.
[IN | OUT | IN OUT] ) ]
RETURN IS
Donde 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;
Resumen PL/SQL III Pgina 6
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
Resumen PL/SQL III Pgina 7
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;
Resumen PL/SQL III Pgina 8
/* 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;
/
Resumen PL/SQL III Pgina 9
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 PRECIOMEDIO;
Resumen PL/SQL III Pgina 10
LITERALES Y CONSTANTES COMO PARMETROS REALES
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;
/
DECLARE
var CONSTANT NUMBER(3,2):=0.16;
BEGIN
TEST1(var);
END;
Resumen PL/SQL III Pgina 11
RESTRICCIONES SOBRE LOS PARMETROS FORMALES
Cuando llamamos a un procedimiento, se pasan los valores de los parmetros reales y dentro
del procedimiento, hacemos referencia a los mismos utilizando los parmetros formales. Las
restricciones sobre las variables tambin se pasan como parte del mecanismo de paso de
parmetros. En la declaracin de un procedimiento no podemos restringir la longitud de los
parmetros de tipo CHAR o VARCHAR2, ni la precisin y/o escala de los de tipo NUMBER,
debido a que las restricciones se tomarn de los parmetros reales.
-- Ejemplo de procedimiento errneo
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
Resumen PL/SQL III Pgina 12
%TYPE Y PARMETROS DE PROCEDIMIENTO
Aunque no podamos declarar parmetros formales con restricciones, estas pueden imponerse
utilizando %TYPE. Si declaramos un parmetro formal con %TYPE, y el tipo al que nos
referimos est restringido, la restriccin actuar sobre el parmetro formal, y no sobre el
parmetro real.
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 ;
ERROR : precisin de nmero demasiado grande numrico o de valor
Resumen PL/SQL III Pgina 13
EXCEPCIONES GENERADAS EN UN SUBPROGRAMA
Si ocurre un error dentro de un subprograma, se genera una excepcin. Si el procedimiento no
tiene control de excepcin, o bien, se genera la rutina de tratamiento de excepciones, se pasa
inmediatamente el control al entorno que efectu la llamada, segn la propagacin de
excepciones. Sin embargo, los valores de los parmetros formales con modo OUT y modo IN
OUT no se devuelven a los parmetros reales.
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;
Resumen PL/SQL III Pgina 14
PASO DE PARMETROS POR REFERENCIA Y POR VALOR
Los parmetros de los subprogramas pueden pasarse por referencia o por valor. Cuando se
pasa un parmetro por referencia, lo que se pasa al parmetro formal correspondiente es un
puntero al parmetro real. Cuando se pasa un parmetro por valor, se copia el valor del
parmetro real al parmetro formal. El paso de parmetro por referencia es generalmente ms
rpido, ya que ahorra la realizacin de la copia, especialmente en el caso de parmetros de
colecciones (tablas, varrays). De forma predeterminada, PL/SQL pasa los parmetros de modo
IN por referencia y los parmetros de modo IN OUT y OUT por valor, para mantener la
semntica de excepciones y para que las restricciones sobre parmetros reales puedan
verificarse.
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
NOCOPY
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.
Resumen PL/SQL III Pgina 15
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;
Resumen PL/SQL III Pgina 16
NOTACIN POSICIONAL Y NOTACIN NOMINAL
Los parmetros formales se encuentran asociados a los parmetros reales por su posicin.
Alternativamente puede realizarse una llamada a un procedimiento utilizando la notacin
nominal, en la cual, para cada argumento, se incluye tanto el parmetro formal, como el
parmetro real, lo que nos permite modificar el orden de los argumentos.
Las notaciones nominal y posicional pueden utilizarse conjuntamente en la misma llamada, en
tal caso, los primeros argumentos a especificar deben ser por posicin.
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;
Resumen PL/SQL III Pgina 17
VALOR PREDETERMINADO DE LOS PARAMETROS
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:
:=
DEFAULT
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
DefaultTest(p_ParametroA => 7, p_ParametroC => '01-FEB-08');
END;
BEGIN
-- Usa el valor predeterminado tanto para p_ParametroB
-- como para p_ParametroC.
DefaultTest(20);
END;
Resumen PL/SQL III Pgina 18
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 IS -- Especificaciones de procedimientos -- Especificaciones de funciones -- Declaraciones de variables -- Declaraciones de excepciones -- Declaraciones de cursores
END [];
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 IS
-- Declaraciones de los subprogramas
END [];
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.
Resumen PL/SQL III Pgina 19
SOBRECARGA DE SUBPROGRAMAS EMPAQUETADOS
Los procedimientos y funciones dentro de un paquete pueden sobrecargarse, lo que significa
que puede haber ms de un procedimiento o una funcin con el mismo nombre, pero con
diferentes parmetros. La sobrecarga est permitida para distinto nmero de parmetros, o
bien, para distinto tipo de familia de dato. No est permitida para diferentes tipos retornados
por una funcin, ni para distintos modos de recepcin de los parmetros (IN, OUT, IN OUT).
INICIALIZACIN DEL PAQUETE
El paquete se instancia la primera vez que se llama a uno de los subprogramas en l
empaquetados, lo que significa que el paquete se lee de disco y se lleva a memoria, y se
ejecuta el cdigo compilado del subprograma al que se llama. En esta situacin se asigna
memoria para todas las variables definidas en el paquete. Cada sesin tendr su propia copia
de las variables empaquetadas, asegurando que dos sesiones que ejecuten subprogramas
contenidos en el mismo paquete utilicen ubicaciones de memoria diferentes.
En ocasiones, es conveniente ejecutar un cdigo de inicializacin la primera vez que se
instancia el paquete, lo que puede hacerse aadiendo una seccin de inicializacin en el
cuerpo del paquete, despus de todos los dems objetos.
CREATE [ OR REPLACE ] PACKAGE BODY IS
BEGIN
-- Cdigo de Inicializacin
END [];
Resumen PL/SQL III Pgina 20
ESPECIFICACIN DEL PAQUETE OPERAR
CREATE OR REPLACE PACKAGE OPERAR IS
FUNCTION SUMAR(N1 IN NUMBER, N2 IN NUMBER) RETURN NUMBER;
FUNCTION SUMAR(N1 IN VARCHAR2, N2 IN VARCHAR2) RETURN VARCHAR2;
FUNCTION RESTAR(N1 IN NUMBER, N2 IN NUMBER) RETURN NUMBER;
FUNCTION DIVIDIR(N1 IN NUMBER, N2 IN NUMBER) RETURN NUMBER;
FUNCTION MULTIPLICAR(N1 IN NUMBER, N2 IN NUMBER) RETURN NUMBER;
RESULTADO NUMBER;
END OPERAR;
CUERPO DEL PAQUETE OPERAR
CREATE OR REPLACE PACKAGE BODY OPERAR IS
FUNCTION SUMAR(N1 IN NUMBER,N2 IN NUMBER) RETURN NUMBER IS
BEGIN
RESULTADO:=N1+N2;
RETURN RESULTADO;
END SUMAR;
FUNCTION RESTAR(N1 IN NUMBER, N2 IN NUMBER) RETURN NUMBER IS
BEGIN
RETURN N1-N2;
END RESTAR;
FUNCTION MULTIPLICAR(N1 IN NUMBER, N2 IN NUMBER) RETURN NUMBER IS
BEGIN
RETURN N1*N2;
END MULTIPLICAR;
FUNCTION DIVIDIR(N1 IN NUMBER, N2 IN NUMBER) RETURN NUMBER IS
BEGIN
RETURN N1/N2;
END DIVIDIR;
FUNCTION SUMAR(N1 IN VARCHAR2, N2 IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN CONCAT(N1,N2);
END SUMAR;
END OPERAR;
EJECUCIN DEL PAQUETE OPERAR
SELECT OPERAR.DIVIDIR (12, 3) FROM DUAL;
SELECT OPERAR.SUMAR (12, 3) FROM DUAL;
SELECT OPERAR.SUMAR ('BUENAS ', 'TARDES') FROM DUAL;
Resumen PL/SQL III Pgina 21
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
BEFORE | AFTER | INSTEAD OF
DELETE | INSERT | UPDATE [OF ]
ON
[ FOR EACH ROW ]
[ WHEN ]
{ }
END [] ;
Resumen PL/SQL III Pgina 22
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 [ , ...]
Ejemplos:
CREATE TRIGGER CAMBIO_CATEGORIA
BEFORE
DELETE OR INSERT OR UPDATE
ON TCATEGORIA
. .
.. ..
END CAMBIO_CATEGORIA;
Resumen PL/SQL III Pgina 23
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')
. .
.. ..
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;
Resumen PL/SQL III Pgina 24
ORDEN DE ACTIVACIN DE LOS DISPARADORES
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.
EJEMPLO ORDEN DE ACTIVACIN
Secuencia
CREATE SEQUENCE trig_seq START WITH 1 INCREMENT BY 1 NOCACHE;
Tabla
CREATE TABLE temp_table
( num_col NUMBER(3),
char_col VARCHAR2(50) ) ;
Resumen PL/SQL III Pgina 25
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;
/
Resumen PL/SQL III Pgina 26
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;
/
Resumen PL/SQL III Pgina 27
Sentencia activadora
Y resultado
UPDATE TProveedores SET poblacion_pr = 'LEGANS' WHERE cod_pr IN ('PCC', 'ASU');
SELECT * FROM temp_table ORDER BY num_col;
Resumen PL/SQL III Pgina 28
EJEMPLO INICIALIZACION DE UN CODIGO
SECUENCIALMENTE
Completa el campo CODIGO_CAT de la tabla de categoras con el prximo valor que genere la
secuencia CODIGO_CAT. Como CODIGO_CAT es una columna la tabla de categoras,
:new.CODIGO_CAT es una referencia vlida.
Secuencia
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 FROM DUAL;
END COD_CAT_NUEVO;
Resumen PL/SQL III Pgina 29
Sentencia activadora
INSERT INTO TCATEGORIA (NOMBRE_CAT ) VALUES ('IMPRESORAS');
Resultado
SELECT * FROM TCATEGORIA ORDER BY CODIGO_CAT ;
IDENTIFICADORES DE CORRELACIN EN DISPARADORES DE NIVEL DE FILA
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.
Resumen PL/SQL III Pgina 30
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 .
REFERENCING [ OLD AS ] [ NEW AS ]
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.
EJEMPLO INICIALIZACION DE UN CODIGO
CLUSULA REFERENCING
Disparador
CREATE OR REPLACE TRIGGER COD_CAT_NUEVO
BEFORE INSERT ON TCATEGORIA
REFERENCING NEW AS CATEGORIA_NUEVA
FOR EACH ROW
BEGIN
SELECT CODIGO_CAT.NEXTVAL INTO :CATEGORIA_NUEVA.CODIGO_CAT FROM DUAL;
END COD_CAT_NUEVO;
Sentencia activadora
INSERT INTO TCATEGORIA (NOMBRE_CAT ) VALUES ('FOTOGRAFA');
Resultado
SELECT * FROM TCATEGORIA ORDER BY CODIGO_CAT ;
Resumen PL/SQL III Pgina 31
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
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.
INSERTING
Verdadero si la instruccin de disparo es INSERT, falso en cualquier otro caso.
UPDATING
Verdadero si la instruccin de disparo es UPDATE.
DELETING
Verdadero si la instruccin de disparo es DELETE.
BEGIN
IF INSERTING THEN
;
ELSIF UPDATING THEN
;
ELSE
;
END IF;
Resumen PL/SQL III Pgina 32
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.
Resumen PL/SQL III Pgina 33
EJEMPLO DISPARADOR DE SUSTITUCIN
Al insertar registros sobre una vista, compuesta por columnas de las tablas proveedores y
pedidos, se ejecutar ste disparador de sustitucin, que se encarga de crear un nuevo
registro en la tabla proveedores y otro nuevo registro en la tabla pedidos.
Vista
CREATE OR REPLACE VIEW PEDIDOS_COMPRA_PROVEEDOR AS
SELECT cif_PC cif, cod_pr cod, nombre_pr nombre, comercial_pc comercial, persona_pr persona,
forma_pago_pc fp
FROM tproveedores INNER JOIN tpedidos_compra ON cif_pr = cif_pc;
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;
Resumen PL/SQL III Pgina 34
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;
Resumen PL/SQL III Pgina 35
TRIGGERS DEL SISTEMA
Tanto los disparadores DML como los de sustitucin se disparan junto con, o en lugar de los
sucesos DML, es decir las instrucciones INSERT, UPDATE o DELETE. Los disparadores del
sistema por el contrario, se disparan a consecuencia de dos tipos de sucesos distintos los DDL,
o los de base de datos. Los sucesos DDL incluyen las instrucciones CREATE, ALTER o DROP,
mientras que los sucesos de base de datos incluyen la conexin y desconexin del servidor, el
inicio y finalizacin de la sesin de usuario y los errores del servidor.
CREATE [OR REPLACE] TRIGGER
BEFORE | AFTER
|
ON DATABASE | [.]SCHEMA
[ WHEN ]
{ PL/SQL Bloque }
. .
END [ ] ;
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.
Resumen PL/SQL III Pgina 36
SUCESOS
STARTUP AFTER Se dispara cuando se inicia una instancia.
SHUTDOWN BEFORE Se dispara cuando se cierra una instancia.
SERVERERROR AFTER Se dispara cuando se produce un error.
LOGON AFTER Se dispara despus de que un usuario se haya conectado a la
base de datos.
LOGOFF BEFORE Se dispara al inicio de la finalizacin de una sesin de usuario.
CREATE BEFORE | AFTER Se dispara antes o despus de la creacin de un objeto en la
base de datos.
DROP BEFORE | AFTER Se dispara antes o despus de la eliminacin de un objeto en la
base de datos.
ALTER BEFORE | AFTER Se dispara antes o despus de la modificacin de un objeto en
la base de datos.
Resumen PL/SQL III Pgina 37
EJEMPLO DISPARADOR DE SISTEMA
Creado como SYSTEM
Tabla
CREATE TABLE temp_table
( num_col NUMBER(3),
char_col VARCHAR2(50) ) ;
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;
Sentencia activadora. Ejecutado como A01
CREATE SEQUENCE SECUENCIA_EJEMPLO
START WITH 10000
INCREMENT BY 1;
Sentencia activadora. Ejecutado como A01
DROP SEQUENCE SECUENCIA_EJEMPLO;
Resultado
SELECT * FROM TEMP_TABLE;
Resumen PL/SQL III Pgina 38
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 ;
Resumen PL/SQL III Pgina 39
FUNCIONES DE ATRIBUTOS DE SUCESOS
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.
Resumen PL/SQL III Pgina 40
EJEMPLO DISPARADOR DE SISTEMA
Creado como SYSTEM
Tabla.
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;
Sentencia activadora. Ejecutado como A01
CREATE SEQUENCE SECUENCIA_EJEMPLO
START WITH 10000
INCREMENT BY 1;
DROP SEQUENCE SECUENCIA_EJEMPLO;
Sentencia activadora. Ejecutado como SYSTEM
CREATE SEQUENCE SECUENCIA_EJEMPLO
START WITH 10000
INCREMENT BY 1;
DROP SEQUENCE SECUENCIA_EJEMPLO;
CREATE SEQUENCE EJEMPLO2
START WITH 10000
INCREMENT BY 1;
DROP SEQUENCE EJEMPLO2;
Resultado
SELECT * FROM NUEVOS_OBJETOS ;
Resumen PL/SQL III Pgina 41
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).
Recommended