Apuntes sobre PL/SQL en Informática
Apuntes sobre PL/SQL en Informática
TRASSIERRA
Crdoba
[Link]
Departamento de Informtica
APUNTES DE PL/SQL
Etapa:
Ciclo:
Nivel:
Superior.
Mdulo:
Bases de Datos.
Profesor:
INDICE:
Tema 1.- PL/SQL ................................................................................................ 1
Tema 2.- Procedimientos, Funciones y Paquetes ........................................... 24
Tema 3.- Disparadores (Triggers) ................................................................. 45
PL/SQL
Dep. Informtica
PL/SQL
Por extensin al SQL, PL/SQL puede acceder a la base de Datos ORACLE porque soporta:
DECLARE
..........
BEGIN
....
DECLARE
BEGIN
....
EXCEPTION
....
END ;
.....
EXCEPTION
............
END ;
Los bloques PL/SQL se pueden anidar tanto en la zona BEGIN como en la EXCEPTION,
pero no en la zona DECLARE, que es nica para cada bloque. Cada bloque debe acabar con
el carcter '/' como nico de la ltima lnea.
Dep. Informtica
PL/SQL
1.3.- TIPOS DE DATOS, CONVERSIONES, MBITO Y VISIBILIDAD.1.3.1.- Tipos de [Link] constante y variable posee un tipo de dato el cual especifica su forma de
almacenamiento, restricciones y rango de valores vlidos. Con PL/SQL se proveen diferentes
tipos de datos predefinidos. Un tipo escalar no tiene componentes internas. Un tipo
compuesto tiene otras componentes internas que pueden ser manipuladas individualmente. Un
tipo referencia almacena valores, llamados punteros, que designan a otros elementos de
programa. Un tipo lob (large object) especifica la ubicacin de un tipo especial de datos que
se almacenan de manera diferente.
En la siguiente figura se muestran los diferentes tipos de datos predefinidos.
NUMRICOS. Binary_integer.- binario con desbordamiento a number. Usado para almacenar enteros
con signo. PL/SQL tiene predefinidos los siguientes subtipos de binary_integer:
NATURAL
NATURALN
POSITIVE
POSITIVEN
SIGNTYPE
Dep. Informtica
No negativo.
No negativo, no admite nulos.
Positivo.
Positivo, no admite nulos.
-1, 0 y 1, usado en lgica trivaluada.
PL/SQL
ALFANUMRICOS.
BOOLEANOS.- Solo pueden tomar 3 valores TRUE, FALSE y NULL. Usados para lgica
trivaluada.
1.3.2.- [Link] de las conversiones explcitas realizadas por las funciones de conversin, cuando se
hace necesario, PL/SQL puede convertir un tipo de dato a otro de forma implcita. Esto
significa que la interpretacin que se dar a algn dato ser la que mejor se adecue
dependiendo del contexto en que se encuentre, por ejemplo cuando variables de tipo char se
operan matemticamente para obtener un resultado numrico.
Si PL/SQL no puede decidir a qu tipos de dato de destino puede convertir una variable se
generar un error de compilacin.
Hasta
Desde
BIN_INT
CHAR
DATE
LONG
NUMBER
PLS_INT
RAW
ROWID
VARCHAR2
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
PL/SQL
1.3.3.- mbito y [Link] de un programa, las referencias a un identificador son resueltas de acuerdo a su mbito
y visibilidad. El mbito de un identificador (variable o constante) es aquella regin de la
unidad de programa (bloque, subprograma o paquete) en la que el identificador mantiene su
valor sin perderlo. La visibilidad se refiere a las zonas en que se puede referenciar (usar).
Los identificadores declarados en un bloque de PL/SQL se consideran locales al bloque y
globales a todos sus sub-bloques anidados. Por eso un mismo identificador no puede declararse
dos veces en un mismo bloque pero s en varios bloques diferentes, cuantas veces se desee.
La siguiente figura muestra el alcance y visibilidad de la variable x, la cual est declarada en
dos bloques cerrados diferentes.
Puede observarse que la variable ms externa tiene un mbito ms amplio pero cuando es
referenciada en el bloque en que se ha declarado otra variable con el mismo nombre, es esta
ltima la que puede ser manipulada y no la primera.
1.4.- ZONA DE [Link] la parte del bloque PL/SQL utilizada cuando es necesario definir variables y/o constantes,
cursores o excepciones. Es una zona opcional de forma que si no hacen falta declaraciones se
omite la palabra reservada DECLARE.
Sintaxis:
DECLARE
declaracin_variables;
declaracin_cursores;
declaracin_excepciones;
PL/SQL
1.4.1.- Declaracin de variables y [Link] variables se utilizan para guardar valores devueltos por una consulta o almacenar clculos
intermedios. Las constantes son campos que se definen y no alteran su valor durante el
proceso.
Sintaxis:
Identificador
[CONSTANT]
<tipo_de_dato /
identificador% TYPE /
identificador% ROWTYPE>
[NOT NULL]
[:= <expresin_plsql / valor_constante>];
dnde:
identificador
[CONSTANT]
tipo_de_dato
identificador%TYPE Declara la variable o constante con el mismo tipo de dato que una
variable definida anteriormente o que una columna de una tabla.
Identificador es el nombre de la variable PL/SQL definida
anteriormente, o el nombre de la tabla y la columna de la base de datos.
Identiticador%ROWTYPE Este atributo declara una fila variable con campos con los
mismos nombres y tipos que las columnas de una tabla o de una fila
recuperada de un cursor. Al declarar una fila %ROWTYPE, no se
admite ni la constante, ni la asignacin de valores.
NOT NULL
[Link]%TYPE ;
number(10,2):=0 ;
char(1) ;
varn_dept%TYPE ;
dept%ROWTYPE ;
1.4.2.- Declaracin de [Link] registros son grupos de variables que pueden recibir la informacin de un cursor. Se
declaran segn la siguiente sintaxis:
TYPE nombre_registro
campo1
campo2
....
var
nombre_registro;
IS RECORD (
[Link]%TYPE
[Link]%TYPE ) ;
Ejemplo:
TYPE
reg
IS RECORD
( empleado
[Link]%TYPE
salario
[Link]% TYPE
r_empleado
reg;
Dep. Informtica
PL/SQL
1.4.3.- Declaracin de [Link] declaracin de un cursor le proporciona un nombre y le asocia una consulta (SELECT). El
cursor es un rea de trabajo que utiliza ORACLE para consultas que devuelven ms de una
fila, permitiendo la lectura y manipulacin de cada una de ellas. Un cursor tiene tres
componentes:
La tabla de resultado obtenida al ejecutar la SELECT.
Un orden establecido entre sus filas.
Un puntero que seala la posicin sobre la tabla resultado.
Tipos de cursores:
Estticos Se declaran en la DECLARE con su clusula SELECT asociada, y se abren,
ejecutan y cierran en la zona BEGN. Pueden ser simples o parametrizados.
Dinmicos La SELECT asociada al cursor no se especifica en la zona DECLARE,
sino en BEGIN, con lo que el resultado de su ejecucin es dinmico. Segn se declare
o no el registro que recibir los datos de la SELECT, los cursores dinmicos pueden
ser prefijados o no prefijados.
Esttico simple
Un cursor esttico simple se declara en la DECLARE con su clusula SELECT y se
abre, ejecuta y cierra en la zona BEGIN.
Sintaxis:
CURSOR
nombre_cursor IS
sentencia SELECT ;
Ejemplo:
DECLARE
CURSOR
SELECT
departa IS
numde, nomde FROM tdepto ;
Esttico parametrizado
Los cursores estticos parametrizados permiten obtener con el mismo cursor diferentes
resultados en funcin del valor que se le pase al parmetro. Su sintaxis es:
CURSOR nombre_cursor (nombre_parmetro tipo_parmetro) IS
sentencia_SELECT_utilizando_los_parmtetros ;
Los parmetros son variables nicamente de entrada, nunca para recuperacin de
datos. Estas variables son locales para el cursor y solo se referencian en la SELECT.
Si se definen parmetros, stos deben especificarse en la SELECT y se utilizan igual
que si utilizsemos un valor constante. Al abrir el cursor se sustituyen los parmetros
por los valores correspondientes.
Ejemplo:
ACCEPT valor PROMPT Departamento:
DECLARE
CURSOR empleados (dept_pl NUMBER) IS
SELECT
numem, nomem
FROM
temple
WHERE
numde = dept_pl ;
..........
BEGIN
OPEN empleados (&valor) ;
-- Apertura del cursor y paso del parmetro
Dep. Informtica
PL/SQL
Si en cualquier cursor quisiramos modificar las filas que nos devuelve, deberamos
aadir a la Select asociada al cursor la clusula:
FOR UPDATE OF nombre_columna ;
Ejemplo:
DECLARE
CURSOR
empleados IS
SELECT numem, nomem FROM temple FOR UPDATE OF nomem ;
Dinmico no prefijado
Los cursores dinmicos son aquellos que la SELECT no aparece en la zona
DECLARE. En los no prefijados no se concreta la proyeccin de la SELECT .
Sintaxis:
TYPE
tipo_cursor IS REF CURSOR ;
...
nombre_cursor tipo_cursor ;
Ejemplo:
DECLARE
TYPE CurEmp IS REF CURSOR
....
C_emple1 CurEmp ;
Dinmico prefijado
Los cursores dinmicos prefijados declaran el registro que va a recibir los datos del
cursor con RETURN <tipo_registro>.
Sintaxis:
Ejemplo:
DECLARE
TYPE
....
[Link]
EXCEPTION ;
El tratamiento de las excepciones, tanto las internas de Oracle como las de usuario, se realiza
en la zona EXCEPTION, y lo veremos en el apartado 1.6.
Dep. Informtica
PL/SQL
1.5.- ZONA DE PROCESO: [Link] esta zona del bloque PL/SQL se escriben todas las sentencias ejecutables. El comienzo del
bloque PL/SQL se especifica con la palabra BEGIN. En el bloque se permiten:
-
1.5.1.- Sentencias propias de PL/[Link] sentencias propias del lenguaje PL/SQL se agrupan en:
Asignaciones
Manejo de cursores
EXIT
Control condicional
Bucles
GOTO
NULL
[Link].- Asignacin.- La asignacin de valores a una variable se hace con el operador ":=".
Algunos ejemplos son:
salario := 2251 ;
comision := substr(cod_postal,2 ,3) ;
aumento := salario * 0.1 ;
total_sueldo := salario + aumento + comision ;
[Link].- Manejo de Cursores.- Los cursores que vayan a utilizarse debern haber sido
definidos en la zona DECLARE.
Para poder realizar una lectura de todas las filas recuperadas en un cursor, es necesario
realizar un bucle. Existen bucles ya predefinidos para recorrer cursores, aunque tambin se
pueden utilizar bucles simples y hacer el recorrido de forma ms controlada.
Para el manejo de los cursores, podemos utilizar los siguientes atributos predefinidos:
%NOTFOUND
%FOUND
Es lo contrario de %NOTFOUND
%ROWCOUNT
%ISOPEN
Para manejar un cursor primero hay que abrirlo (OPEN), luego leerlo (FETCH) y por ltimo
cerrarlo (CLOSE).
Dep. Informtica
PL/SQL
Sintaxis
OPEN nombre_cursor ;
cursor dinmico
Leer el Cursor: FETCH. La sentencia FETCH, recupera la siguiente fila del cursor hasta
detectar el final. Los datos recuperados deben almacenarse en variables o registros.
Sintaxis para recuperacin en variables:
FETCH nombre_cursor INTO var1 [,var2] ;
Todas las variables que aparecen en la clusula INTO deben haber sido definidas
previamente en la zona de declaracin de variables DECLARE.
Ser necesario tener tantas variables como columnas estemos recuperando en la
SELECT asociada al cursor. La recuperacin es posicional, es decir la primera
columna seleccionada se almacenar en la primera variable, la segunda en la segunda,
y as sucesivamente, por lo tanto, los tipos de las variables debern ser compatibles
con los valores de las columnas que van a almacenar.
Sintaxis para recuperacin en registro:
FETCH nombre_cursor INTO nombre_registro ;
Es la sintaxis ms usada debido a la facilidad para declarar el registro en la zona
DECLARE con la opcin de atributo %ROWTYPE<nombre_tabla>/<nombre_cursor>.
En la zona BEGIN, y mientras el cursor est abierto, las columnas del cursor pueden
utilizarse haciendo referencia al nombre del registro, del que son variables miembro. En
el supuesto del prrafo anterior, y caso de que la select asociada al cursor tenga
columnas con expresiones distintas a nombres de columna (SUM(salar), por ejemplo),
debern usarse alias de columna, por cuyo nombre sern referenciadas.
Dep. Informtica
10
PL/SQL
Ejemplo:
DECLARE
CURSOR curdep IS
SELECT numde, nomde, presu FROM tdepto ;
reg_dept curdep%ROWTYPE ;
BEGIN
FETCH curdep INTO reg_dept ;
IF reg_dep.numde < 150 THEN ...
Cerrar el Cursor: CLOSE. La sentencia CLOSE cierra el cursor. Una vez cerrado no se
puede volver a leer (FETCH), pero si se puede volver a abrir. Cualquier operacin que se
intente realizar con un cursor cerrado, provoca la excepcin predefinida INVALID_CURSOR.
Sintaxis : CLOSE
nombre_cursor ;
condicin
THEN sentencias ;
condicin
THEN sentencias ;]
sentencias ;]
IF tipo = 1
ELSIF tipo = 2
ELSE
END IF ;
Bucles bsicos
Bucles condicionales (WHILE)
Bucles numricos (FOR)
Bucles sobre cursores
Bucles para una SELECT
Dep. Informtica
11
PL/SQL
a>0
LOOP
a := a - 1 ;
END LOOP ;
Bucles Numricos (FOR). Son bucles que se ejecutan una vez para cada elemento
definido dentro del rango numrico. Su sintaxis es:
FOR ndice IN [REVERSE] exp_n1 .. exp_n2
LOOP
Sentencias ;
END LOOP ;
ndice
REVERSE
Bucles sobre Cursores. Son bucles que se ejecutan para cada fila del cursor. Cuando se
inicia un bucle sobre un cursor automticamente se realizan los siguientes pasos:
- Se declara implcitamente el registro especificado como nombre_cursor%ROWTYPE.
- Se abre el cursor.
- Se realiza la lectura y se ejecutan las sentencias del bucle hasta que no hay mas filas.
- Se cierra el cursor.
Dep. Informtica
12
PL/SQL
Sintaxis:
FOR nombre_registro IN nombre_cursor
LOOP
Sentencias ;
END LOOP ;
La variable de control del bucle se incrementa automticamente y no es necesario
inicializarla, pues lo est implcitamente como variable local de tipo integer. El mbito del
contador es el bucle y no puede accederse a su valor fuera de l. Dentro del bucle, el
contador puede referenciarse como una constante pero no se le puede asignar un valor.
Tambin le podemos pasar parmetros al cursor, tal y como se indic en el apartado de
manejo de cursores. En este caso los parmetros se indican entre parntesis tras el nombre
del cursor:
FOR nombre_registro IN nombre_cursor(lista_de_parametros)
.......
Si se sale del bucle prematuramente (p.e. con EXIT), o se detecta un error (excepcin), el
cursor se cierra.
Ejemplo:
DECLARE
CURSOR curdep IS
SELECT
numde, nomde FROM tdepto;
reg_dept
curdep%ROWTYPE ;
-- (*)
BEGIN
FOR reg_dept IN curdep
LOOP
......;
END LOOP;
(*) Esta sentencia sobra, pues es declarada implcitamente por este tipo de bucle.
Bucles para Sentencias SELECT. Es el mismo concepto que el del cursor, excepto que
en vez de declarar un cursor con su SELECT, se escribe directamente la sentencia
SELECT y Oracle utiliza un cursor interno para hacer la declaracin. Su sintaxis es:
FOR nombre_registro IN sentencia_SELECT
LOOP
sentencias ;
END LOOP ;
Si se sale del bucle prematuramente, o se detecta un error, el cursor se cierra. Hay que
resaltar que las columnas del cursor no pueden ser usadas con <[Link]> fuera
de estos dos ltimos bucles, ya que cierran automticamente el cursor que tratan.
Ejemplo:
FOR
registro IN SELECT numde FROM tdepto
LOOP
sentencias ;
END LOOP ;
Dep. Informtica
13
PL/SQL
[Link].- GOTO. Esta sentencia transfiere el control a la sentencia o bloque PL/SQL siguiente
a la etiqueta indicada. Su sintaxis es:
GOTO etiqueta;
La etiqueta se especifica entre los smbolos << y >>, por ejemplo:
GOTO A
.....
<<A>>
La sentencia GOTO puede ir a otra parte del bloque o aun sub-bloque, pero nunca podr ir a
la zona de excepciones. La sentencia siguiente a una etiqueta debe ser ejecutable. En caso de
no existir, por ejemplo por ser el final del programa, se puede utilizar la sentencia NULL.
[Link].- NULL. Significa inaccin. El nico objeto que tiene es pasar el control a la siguiente
sentencia. Su sintaxis es:
NULL
Ejemplo:
IF tipo = 1
THEN vsal := vsal * 0.01
ELSE NULL;
END IF;
%FOUND
%ROWCOUNT
[Link].- SELECT.
La sentencia SELECT recupera valores de la Base de Datos que sern almacenados en
variables PL/SQL. La sintaxis completa de la SELECT ya se estudi en la parte de SQL, la
nica variante en programacin es la opcin INTO que permite almacenar los valores
recuperados en variables.
Para poder recuperar valores en variables, la consulta slo debe devolver una fila (no funciona
con predicados de grupo). Su sintaxis es:
SELECT
FROM
Dep. Informtica
14
PL/SQL
[Link].- INSERT.
INSERT crea filas en la tabla o vista especificada. Su sintaxis es idntica a la de SQL.
Se puede realizar el INSERT con valores de las variables PL/SQL o con los datos de una
SELECT. En este caso hay que tener en cuenta que sta ltima no lleva clusula INTO.
En ambos casos el nmero de columnas a insertar deber ser igual al nmero de valores y/o
variables o a las columnas especificadas en la SELECT. En caso de omitir las columnas de la
tabla en la que vamos a insertar, se debern especificar valores para todas las columnas de la
tabla y en el mismo orden en el que esta haya sido creada.
Su sintaxis es la misma de SQL:
INSERT INTO tabla [ (col1 [,col2] .....) ]
{ VALUES (exp1 [,exp2]..... ) /
Sentencia_Select
};
VALUES
Sentencia_Select
Dep. Informtica
15
PL/SQL
SQL%NOTFOUND es FALSE
SQL%FOUND es TRUE
SQL%ROWCOUNT es nmero de filas insertadas
Ejemplo:
DECLARE
x number(2) := 80;
y char(14) := 'INFORMATICA';
c char(13) := 'MADRID';
BEGIN
INSERT INTO dept (loc, dep_no, dname) VALUES (c, x, y);
x := 90;
y := 'PERSONAL'
c := 'MALAGA'
INSERT INTO dept (loc, dep_no, dname) VALUES (c, x, y);
INSERT INTO dept (loc, dep_no, dname) VALUES (92, 'ADMINISTRACION', 'SEVILLA') ;
END;
[Link].- UPDATE
La sentencia UPDA TE permite modificar los datos almacenados en las tablas o vistas.
Sintaxis:
UPDATE
SET
tabla
columna = { sentencia select /
expresin_plsql /
constante /
variable_plsql
}
[ WHERE
{
condicin / CURRENT OF nombre_cursor} ] ;
La clusula WHERE CURRENT OF debe ser utilizada despus de haber realizado la lectura
del cursor que debe haber sido definido con la opcin FOR UPDATE OF. Esta clusula no es
admitida en cursores cuya select utilice varias tablas (obtenidos con select con yuncin).
Si no se actualiza ninguna fila los atributos devuelven los siguientes valores:
SQL%NOTFOUND es TRUE
SQL %FOUND es FALSE
SQL %ROWCOUNT es 0
Si se actualizan una o ms filas los atributos devuelven los siguientes valores:
SQL %NOTFOUND es FALSE
SQL%FOUND es TRUE
SQL%ROWCOUNT el nmero de filas actualizadas
Ejemplo:
UPDATE
temple
SET salar = salar * 0.1 WHERE numde = 110 ;
Dep. Informtica
16
PL/SQL
[Link].- DELETE.
La sentencia DELETE permite borrar filas de la tabla o vista especificada.
Sintaxis:
DELETE
[ FROM]
[ WHERE
tabla
{condicin / CURRENT OF nombre_cursor} ] ;
Al igual que con UPDATE, la clusula WHERE CURRENT OF debe ser utilizada despus de
haber ledo el cursor que debe haber sido definido con la opcin FOR UPDATE OF.
Si no se borra ninguna fila los atributos devuelven los siguientes valores:
SQL%NOTFOUND es TRUE
SQL%FOUND es FALSE
SQL%ROWCOUNT es 0
Si se borran una o ms filas los atributos devuelven los siguientes valores:
SQL%NOTFOUND es FALSE
SQL%FOUND es TRUE
SQL%ROWCOUNT es nmero de filas borradas
Ejemplo:
DELETE
WHERE
FROM temple
numde = 110;
1.6.- ZONA DE EXCEPCIONES: [Link] zona de excepciones es la ltima parte del bloque PL/SQL y en ella se realiza la gestin y
el control de errores.
Con las excepciones ser pueden manejar los errores cmodamente sin necesidad de mantener
mltiples chequeos por cada sentencia escrita. Tambin provee claridad en el cdigo ya que
permite mantener las rutinas correspondientes al tratamiento de los errores en forma separada
de la lgica del negocio.
Sintaxis:
EXCEPTION control_de_errores ;
Dep. Informtica
17
PL/SQL
nombre_excepcin
sentencias
SQLCODE
-6511
-1
-1001
-1722
-1017
+100
-1012
-6501
-6500
-51
-1422
-6502
-1476
Dep. Informtica
18
PL/SQL
Otras excepciones.
Se trata de un control de errores para el usuario. Este tipo de excepciones se deben
declarar segn vimos en el apartado de DECLARE. Una vez declarada la excepcin, la
podemos provocar cuando sea necesario utilizando la funcin RAISE que se detalla a
continuacin. El tratamiento dentro de la zona de excepciones es exactamente igual que el
de una excepcin predefinida.
Sintaxis: DECLARE
A EXCEPTION;
BEGIN
RAISE A;
EXCEPTION
WHEN A THEN .... ;
END;
RAISE
nombre_excepcin
DECLARE
error EXCEPTION;
BEGIN
RAISE error;
RAISE TOO_MANY _ROWS;
EXCEPTION
WHEN error THEN ...;
WHEN TOO_MANY _ROWS THEN ... ;
END;
1.6.5.- [Link] funcin SQLCODE nos devuelve el nmero del error que se ha producido. Slo tiene valor
cuando ocurre un error Oracle.
Esta funcin solo se habilita en la zona de Excepciones, ya que es el nico sitio donde se
pueden controlan los errores.
No se puede utilizar directamente, pero si se puede guardar su valor en una variable.
Dep. Informtica
19
PL/SQL
1.6.6.- [Link] funcin SQLERRM devuelve el mensaje del error del valor actual del SQLCODE.
Al igual que SQLCODE, no se puede utilizar directamente, sino que debemos declarar una
variable alfanumrica lo suficientemente grande para contener el mensaje de error.
EXCEPTION
WHEN OTHERS THEN
err_num := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 100);
INSERT INTO errores VALUES(err_num, err_msg);
END;
Dep. Informtica
20
PL/SQL
4.- Ante la inexistencia de cualquier error se manda un mensaje al buffer de salida que
ser visualizado al final del programa:
SET SERVEROUTPUT ON SIZE 5000
DECLARE
cur1 IS ..........
no_existe EXCEPTION ;
BEGIN
OPEN cur1;
FETCH cur1 INTO registro;
IF cur1%NOTFOUND THEN
RAISE no_existe;
END IF;
........
EXCEPTION
WHEN no_existe THEN
DBMS_OUTPUT.PUT_LINE('Empleado inexistente');
END;
1.7.- EJERCICIOS.1.7.1.- EJERCICIOS RESUELTOS.1.- Programa que haciendo uso de un bucle simple, inserte sucesivamente tuplas con el valor
de un contador entre 1 y 14 en la tabla TEMPORAL, previamente creada y con una sola
columna: NUMERO number(2).
DROP TABLE temporal ;
CREATE TABLE temporal (numero number(2));
DECLARE
i number(2):=1;
BEGIN
LOOP
INSERT INTO temporal VALUES (i);
i:=i+1;
EXIT WHEN i>14;
END LOOP;
END;
/
SELECT * FROM temporal ;
Dep. Informtica
21
PL/SQL
4.- Programa que crea la tabla TEST, con dos nicas columnas numricas de longitud 3: NR1
y NR2. Y posteriormente asigna a NR1 un valor decreciente del 19 hasta el cero, y a NR2 el
valor de un contador creciente de 1 a 20. Y ello con el uso de un bucle de cursor.
DROP TABLE test;
CREATE TABLE test (nr1 NUMBER(3), nr2 NUMBER(3)) ;
BEGIN
-- inserta valores en la tabla TEST
FOR i IN 1..20 LOOP
INSERT INTO test values( NULL, i) ;
END LOOP;
COMMIT;
END;
/
DECLARE
x NUMBER(4) := 0;
CURSOR t_cur IS
SELECT * FROM test ORDER BY nr2 desc FOR UPDATE OF nr1;
BEGIN
FOR t_rec IN t_cur LOOP
UPDATE test SET nr1 = x WHERE CURRENT OF t_cur;
x := x + 1;
END LOOP;
COMMIT;
END;
/
SELECT * FROM test ;
SET ECHO OFF;
1.7.2.- EJERCICIOS PROPUESTOS.1.- Codificar el programa PL/SQL que permita aumentar en un 10% el salario de un empleado
cuyo nmero se introduce por teclado.
2.- Modificar el anterior programa para controlar la inexistencia del empleado tecleado, no
haciendo nada, solo evitando que el programa finalice con error.
3.- Modificar el anterior programa de forma que si el empleado no existe se visualice un
mensaje de error.
Dep. Informtica
22
PL/SQL
4.- Codificar el programa PL/SQL que solicite por pantalla un nmero de departamento y
calcule la suma total de los salarios y comisiones de ese departamento. Despus inserte la
tupla correspondiente en la tabla TOTALES, previamente creada con la siguiente estructura:
deptno
number(3)
total
number(10,2)
Dep. Informtica
23
PL/SQL
2.1.- [Link] de los bloques de cdigo ya vistos, Oracle permite desarrollar subprogramas, es
decir, agrupar una serie de definiciones y sentencias para ejecutarlas bajo un nico nombre,
estos subprogramas son: procedimientos, funciones y paquetes.
Los procedimientos son trozos de cdigo que realizan un trabajo sobre unos argumentos de
entrada que son opcionales y depositan unos valores sobre unos argumentos de salida,
tambin opcionales.
Las funciones son similares a los procedimientos con la diferencia de que devuelven siempre
un valor.
Los paquetes son agrupaciones de procedimientos, funciones y definiciones de datos; es lo
que en otros entornos de programacin se conoce como librera.
Tanto los procedimientos como las funciones disponen de la siguiente estructura:
cabecera del procedimiento o funcin
declaracin de variables, cursores, sobprocedimientos, etc.
BEGIN
zona ejecutable
EXCEPTION
manipuladores de excepciones
END [nombre_procedimiento] ;
Dep. Informtica
24
PL/SQL
Desarrollar un subprograma para almacenar un bloque PL/SQL en la base de datos es muy til
cuando es necesario ejecutarlo repetidamente. Un subprograma puede invocarse desde
multitud de entornos: SQL *Plus, Oracle Forms, otro subprograma, y desde cualquier otra
herramienta o aplicacin Oracle.
Para crear un procedimiento o funcin hay que seguir los pasos siguientes:
1.- Escribir el texto de la sentencia CREATE PROCEDURE / FUNCTION y guardarlo
en un fichero de texto con la extensin .SQL. Mientras se compone esta sentencia se
debe ir pensando en el manejo de errores de ejecucin.
Es importante que los ficheros de texto acaben con una lnea que contenga el carcter
'/' como nico carcter de la columna uno. Por ejemplo (la tabla alumnos debe estar
creada):
CREATE PROCEDURE altalum (v_num number, v_nom varchar2) IS
BEGIN
INSERT INTO alumnos VALUES (v_num, v_nom);
END ;
/
La mayora de las aplicaciones Oracle, entre ellas SQLPls, permiten el paso de parmetros
posicionalmente o por asociacin de nombres (de forma similar a la apertura de cursores
parametrizados), incluso de forma mixta.
Supongamos que tenemos las variables v_a de tipo number y v_b de tipo char:
SQL>variable v_a number;
SQL>variable v_b varchar2(50);
SQL>execute :v_a:=2;
SQL>execute :v_b:= 'ANA PALACIOS';
Dep. Informtica
25
PL/SQL
2.2.- [Link] procedimiento es un subprograma que realiza una accin especfica. Pueden recibir
parmetros pero que no devuelven ningn valor.
2.2.1.- Creacin y [Link] crea un nuevo procedimiento con la sentencia CREATE PROCEDURE, que declara una
lista de argumentos y define la accin a ejecutar por el bloque PL/SQL estndar.
Sintaxis:
CREATE [OR REPLACE] PROCEDURE nombre_proc
( argumento [tipo_arg] tipo_dato [,argumento [tipo] tipo_dato ] .... )
AS [IS] bloque PL/SQL
dnde:
nombre_proc
argumento
tipo_arg
tipo_dato
2.2.2. Tipos de [Link] nmero de argumentos y sus tipos de datos deben corresponderse con los de los parmetros
que se le pasan al procedimiento, pero los nombres puede ser diferentes. Esto permite que el
mismo procedimiento pueda invocarse desde diferentes lugares.
Para transferir valores desde y hacia el entorno de llamada a travs de argumentos debemos
escoger entre uno de los tres tipos de argumento: In, Out e In Out.
Dep. Informtica
26
PL/SQL
Tipo
IN
Descripcin
Se usa para pasar parmetros por valor. El parmetro acta como
constante por lo que no se le puede asignar ni cambiar su valor
dentro del procedimiento. Este parmetro puede referenciarse en la
llamada mediante una constante, variable inicializada o expresin.
OUT
IN OUT
Los parmetros pueden declararse para que tomen valores por defecto, veamos como:
CREATE PROCEDURE prueba(v1 varchar2 default 'Sin Nombre', v2 number default 5) is ..
Las llamadas vlidas que podemos hacer a este procedimiento son las siguientes:
EXECUTE prueba;
EXECUTE prueba ('Paco');
EXECUTE prueba ('Marta', 9);
Dep. Informtica
27
PL/SQL
BEGIN
INSERT INTO temple
VALUES (v_emp_numero, v_emp_departa, v_emp_telefono, v_emp_fechanac,
v_emp_fechaing, v_emp_salario, v_emp_comision, v_emp_hijos, v_emp_nombre) ;
COMMIT WORK ;
END alta_emp ;
/
Recordemos que la orden show errors es muy til para depurar el cdigo. Si todo va bien nos
aparecer el mensaje de Procedimiento creado. Ahora para ejecutarlo debemos escribir la
sentencia execute, por ejemplo:
EXECUTE alta_emp(555, 111, 780, '24/06/1979', sysdate, 777, null, 3, 'ARGUDO, MANUEL')
lo que provocar la ejecucin del procedimiento y por ende el alta del empleado tecleado.
Se pueden eliminar valores innecesarios de entrada a los procedimientos derivando dichos
valores internamente dentro del procedimiento o relacionndolos con un valor por defecto de
columna al definir la tabla. Por ejemplo para:
-
El siguiente ejemplo elimina los valores de entrada innecesarios en una rutina de altas de
empleados, dejando solo como variables de entrada la informacin esencial:
CREATE OR REPLACE PROCEDURE alta_emp (v_emp_numero
v_emp_departa
v_emp_telefono
v_emp_fechanac
v_emp_hijos
v_emp_nombre
v_emp_fechaing [Link]%TYPE ;
v_emp_salario [Link]%TYPE ;
v_emp_comision [Link]%TYPE ;
BEGIN
v_emp_fechaing := SYSDATE ;
IF (v_emp_departa IN (110, 111, 112)) THEN
v_emp_comision := 0 ;
ELSE v_emp_comision := NULL;
END IF;
IN [Link]%TYPE ,
IN [Link]%TYPE ,
IN [Link]%TYPE ,
IN [Link]%TYPE ,
[Link]%TYPE ,
[Link]%TYPE ) IS
SELECT
min(salar) INTO v_emp_salario
FROM temple
WHERE
numde = v_emp_departa ;
INSERT
INTO temple VALUES (v_emp_numero, v_emp_departa, v_emp_telefono,
v_emp_fechanac, v_emp_fechaing, v_emp_salario,
v_emp_comision, v_emp_hijos, v_emp_nombre) ;
COMMIT WORK ;
END alta_emp ;
/
Dep. Informtica
28
PL/SQL
Argumentos OUT
Recuperar valores desde un procedimiento a el entorno de llamada a travs de argumentos
OUT. En el siguiente ejemplo, recuperar informacin sobre un empleado.
CREATE OR REPLACE PROCEDURE consulta_emp
(v_emp_numero IN [Link]%TYPE ,
v_emp_nombre OUT [Link]%TYPE ,
v_emp_salario OUT [Link]%TYPE ,
v_emp_comision OUT [Link]%TYPE) IS
BEGIN
SELECT nomem, salar, comis INTO v_emp_nombre, v_emp_salario, v_emp_comision
FROM temple WHERE numem = v_emp_numero;
END consulta_emp;
/
Para invocar a este procedimiento hay que pasarle todos los parmetros, ya sean IN, OUT o
IN OUT. Aunque lo habitual es invocar a un procedimiento desde un bloque PL, el siguiente
ejemplo muestra la forma de invocarlo con argumentos IN y OUT desde el prompt de SQL:
SQL> var x varchar2(50);
SQL> var y number;
SQL> var z number;
SQL> execute consulta_emp(390, :x, :y, :z);
Incluso podramos ver el contenido de las variables OUT modificadas por el procedimiento.
SQL> PRINT :x; .......
Argumentos IN OUT
El siguiente ejemplo transforma una secuencia de nueve dgitos en un numero de telfono.
Recupera valores desde el entorno de trabajo hacia el procedimiento, y devuelve los diferentes
valores posibles desde el procedimiento al entorno de llamada utilizando argumentos IN
OUT.
CREATE OR REPLACE PROCEDURE con_guion
(v_telf_no
IN OUT VARCHAR2 )
IS
BEGIN
v_telf_no := SUBSTR (v_telf_no, 1, 3) || '-' || SUBSTR(v_telf_no, 4);
END con_guion;
/
El valor de un argumento tipo IN OUT debe darlo el procedimiento, bien mediante una
sentencia de asignacin, o bien por mediante una sentencia SELECT .. INTO.
2.2.3.- [Link] polimorfismo es una caracterstica que permite definir ms de un objeto con el mismo
nombre. En PL/SQL podemos definir distintas funciones y procedimientos que compartan un
nombre comn, pero han de diferenciarse en la cantidad o tipo de los parmetros que reciben
o devuelven.
Dep. Informtica
29
PL/SQL
Ejemplo:
PROCEDURE initialize (tab OUT DateTabTyp, n INTEGER) IS
BEGIN
FOR i IN 1..n LOOP
tab(i) := SYSDATE;
END LOOP;
END initialize;
PROCEDURE initialize (tab OUT RealTabTyp, n INTEGER) IS
BEGIN
FOR i IN 1..n LOOP
tab(i) := 0.0;
END LOOP;
END initialize;
Estos procedimientos slo difieren en el tipo de dato del primer parmetro. Para efectuar una
llamada a cualquiera de ellos, se puede implementar lo siguiente:
DECLARE
TYPE DateTabTyp IS TABLE OF DATE INDEX BY BINARY_INTEGER;
TYPE RealTabTyp IS TABLE OF REAL INDEX BY BINARY_INTEGER;
hiredate_tab
DateTabTyp;
comm_tab
RealTabTyp;
indx
BINARY_INTEGER;
BEGIN
indx := 50;
initialize(hiredate_tab, indx);
-- llama a la primera versin
initialize(comm_tab, indx);
-- llama a la segunda versin
...
END;
2.3.- [Link] funciones son subprogramas que reciben parmetros y devuelven un nico valor. Desde el
punto de vista estrictamente sintctico, un procedimiento conteniendo un argumento OUT
puede ser reescrito como una funcin, y uno que contenga argumentos OUT mltiples puede
reescribirse como una funcin que devuelva un argumento tipo registro. El como de largo ser
la invocacin de la rutina, es lo que determina que su implementacin se realice mediante un
procedimiento o una funcin.
Lo normal ser que sus argumentos sean de tipo IN. Los de tipo OUT o IN OUT, aunque son
vlidos dentro de las funciones, se utilizan raras veces.
2.3.1.- Creacin y [Link] sentencia CREATE FUNCTION es idntica a CREATE PROCEDURE, excepto por la
clusula extra RETURN. Con ella se genera una nueva funcin que declara una lista de
argumentos, declara el argumento RETURN y define la accin a realizar por el bloque
PL/SQL estndar. Su sintaxis es:
CREATE [OR REPLACE] FUNCTION nombre_func
(argumento [tipo] tipo_dato [,argumento [tipo] tipo_dato ] ..) RETURN tipo_dato
AS [IS] bloque PL/SQL
Dep. Informtica
30
PL/SQL
Dnde los elementos significan lo mismo que en la sentencia CREATE PROCEDURE, salvo:
RETURN tipo_dato que indica el tipo de dato devuelto por la funcin. Este tipo de dato no
puede incluir escala o precisin.
En una funcin puede haber varias sentencias RETURN, con la nica condicin de que al
menos haya una.
Ejemplo: recuperar el salario de un empleado.
CREATE OR REPLACE FUNCTION tomar_salario
(v_emp_numero IN [Link]%TYPE) RETURN number
IS
v_emp_salario [Link]%TYPE := 0;
BEGIN
SELECT
FROM
WHERE
RETURN
END tomar_salario;
/
Al igual que los procedimientos, las funciones pueden invocarse pasndoles los parmetros
con notacin posicional, nominal o mixta, y se les pueden asignar valores por defecto.
Para borrar una funcin usaremos la sentencia:
DROP FUNCTION nombre_func ;
2.3.2.- [Link] funciones pueden invocarse recursivamente, tanto en autollamada como en interllamada.
Veamos la tpica funcin de factorial (autoinvocacin):
CREATE FUNCTION factorial (n number) RETURN number IS
BEGIN
IF n = 0 THEN RETURN 1;
ELSE
RETURN n* factorial (n-1);
END IF;
END ;
/
Como las funciones devuelven un valor, si queremos llamar a una funcin desde el prompt de
SQL debemos declarar una variable para almacenar dicho valor y posteriormente visualizarlo:
SQL> variable v number;
SQL> EXECUTE :v:=factorial(4);
SQL> print v;
Dep. Informtica
31
PL/SQL
La versin recursiva es ms elegante que la iterativa, sin embargo esta ltima es ms eficiente,
corre ms rpido y utiliza menos memoria.
2.3.3.- Funciones PL/SQL en sentencias [Link] de una expresin SQL se pueden referenciar funciones definidas por el usuario. Donde
pueda haber una funcin SQL, puede situarse tambin una funcin PL/SQL. Para invocar una
funcin desde una sentencia SQL se debe ser el propietario de la funcin o tener el privilegio
EXECUTE. Las situaciones en que puede invocarse una funcin de usuario son las
siguientes:
La lista de expresiones del comando SELECT.
Condiciones de las clusulas WHERE y HAVING.
La clusula VALUES de la sentencia INSERT.
La clusula SET de la sentencia UPDATE.
NO se puede invocar una funcin PL/SQL desde la clusula CHECK de una vista.
Dep. Informtica
32
PL/SQL
Para poder invocar desde una expresin SQL, una funcin PL/SQL definida por el usuario
debe cumplir ciertos requerimientos bsicos.
Debe ser una funcin almacenada, no una funcin dentro de un Bloque PL/SQL
annimo o un subprograma.
Debe ser una funcin de fila nica y NO una funcin de columna (grupo). Esto ocurre
porque no se puede tomar el valor de todos los datos de una columna como argumento.
Todos los argumentos deben ser del tipo IN. No se admiten los tipos OUT o IN OUT.
Los tipos de datos de los argumentos deben ser tipos de datos internos del Servidor
Oracle, tales como CHAR, DATE o NUMBER, y no tipo PL/SQL como BOOLEAN,
RECORD o TABLE.
Para ejecutar una sentencia SQL que llama a una funcin almacenada, el servidor Oracle debe
conocer si la funcin provoca efectos colaterales. stos pueden ser cambios en tablas de la
base de datos o en variables pblicas de paquetes (que se declaran en la zona de
especificacin del paquete). Los efectos colaterales pueden aplazar la ejecucin de una
consulta, producir resultados dependientes del orden (por lo tanto indeterminados), o requerir
que el estado del paquete se deba mantener a travs de las sesiones de usuario (lo cual no est
permitido). Por ello, las siguientes restricciones se aplican a funciones almacenadas
invocadas desde expresiones SQL:
Las funciones no pueden modificar datos en las tablas. No pueden ejecutar INSERT,
UPDATE o DELETE.
Las funciones remotas no pueden leer, ni escribir el estado de un paquete. Cada vez
que se accede aun enlace de base de datos, se establece una nueva sesin en la base de
datos remota.
2.4.- [Link] paquetes son un conjunto de procedimientos, funciones y datos. Un paquete es muy
similar a una librera con la ventaja de que podemos ocultar informacin, ya que se compone
de una parte de declaraciones visibles desde el exterior y una serie de implementaciones a las
que no puede accederse desde fuera sino es a travs del interfaz declarado en la parte pblica.
Las ventajas que ofrecen los paquetes son: modularidad, facilidad en el diseo de
aplicaciones, ocultamiento de la informacin, aaden funcionalidad al sistema, y mejoran el
rendimiento ya que la primera llamada a la librera carga sta en memoria, de forma que las
sucesivas invocaciones se evitan acceder a disco.
Dep. Informtica
33
PL/SQL
2.4.1.- Creacin y [Link] paquetes se crean con el comando CREATE PACKAGE, cuya sintaxis es:
- Parte de declaraciones:
CREATE [OR REPLACE] PACKAGE nombre_paq
AS [IS] bloque_pl_sql_paq_decl
- Cuerpo del paquete (implementacin):
CREATE [OR REPLACE] PACKAGE body nombre_paq
AS [IS] bloque_pl_sql_paq_body
Un paquete puede contener procedimientos, funciones, variables, constantes, cursores y
excepciones. Adems, siempre que no se cambie la parte de declaraciones, se puede cambiar
la implementacin de una rutina o el cuerpo de un cursor sin necesidad de volver a compilar
las aplicaciones que los usaban, ya que el interfaz no se ha cambiado.
Un paquete presenta normalmente el siguiente formato:
create package nombre is
/* especificacin (parte visible) */
/* declaraciones de tipos y objetos pblicos */
/* especificacin de procedimientos y funciones */
end;
/
create package body nombre is
/* cuerpo (parte oculta)*/
/*declaraciones de tipos y objetos privados */
/* implementacin de procedimientos y funciones */
[ begin
/* sentencias de inicializacin */ ]
end;
/
En la cabecera del paquete se especifican todos aquellos objetos a los que se puede acceder, y
en el cuerpo del paquete se implementan dichos objetos. En el cuerpo podemos declarar e
implementar cuantos objetos estimemos oportunos teniendo en cuenta que a ellos solo se va a
poder acceder desde el cuerpo del paquete.
El cuerpo del paquete puede incluir opcionalmente una zona de inicializacin (BEGIN...) que
Solo se ejecuta la primera vez que se hace referencia al paquete dentro de una misma sesin.
Ya sabemos que los procedimientos y las funciones se declaran con la palabra reservada
CREATE y se invocan con EXECUTE. Esto es as cuando los creamos desde el prompt de
SQL, pero dentro de un paquete no hay que poner ni CREATE OR REPLACE, ni EXECUTE.
Una vez que tenemos un paquete creado y compilado podemos acceder a los objetos
declarados en la parte visible desde el prompt de SQL o desde otros procedimientos y
funciones; para ello tan solo hay que anteponerle al nombre del procedimiento o funcin el
nombre del paquete que lo contiene separado por un punto.
/* para el caso de que la llamada se haga desde el prompt de SQL*/
SQL > execute nombre_paquete.nombre_procedimiento(argumentos);
Dep. Informtica
34
PL/SQL
2.4.2.- La depuracin en los [Link] objeto de identificar los errores en tiempo de compilacin, en vez de esperar a la ejecucin,
puede especificarse el nivel de depuracin de una funcin empaquetada cuando se crea el
paquete. El nivel de depuracin determina que operaciones puede realizar la funcin en la
base de datos. Para especificar en nivel de depuracin se utiliza el paquete predefinido
RESTRICT_REFERENCES.
Sintaxis:
PRAGMA RESTRICT_REFERENCES ( nombre_func, WNDS
[,WNPS] [RNDS] [,RNPS] ) ;
Donde:
WNDS
WNPS
RNDS
RNPS
Dep. Informtica
35
PL/SQL
Este paquete sirve para alertar a los desarrolladores de aplicaciones con cdigo procedural que
incumplen las restricciones de las funciones PL/SQL dentro de sentencias SQL.
Indica al compilador PL/SQL qu tipo de acciones pueden realizar las funciones. Las
sentencias SQL que incumplan estas reglas producen un error de compilacin.
Ejemplo: Crear una funcin llamada COMP, dentro del paquete FINANZAS. La funcin ser
invocada desde sentencias SOL en bases de datos remotas. Por lo tanto ser necesario indicar
los niveles de depuracin RNPS y WNPS porque las funciones remotas no pueden nunca
escribir o leer el estado del paquete cuando se le invoca desde una sentencia SQL.
CREATE PACKAGE finanzas AS
interes REAL;
FUNCTION comp
(anos IN NUMBER
cant
IN NUMBER
porc
IN NUMBER) RETURN NUMBER;
PRAGMA RESTRICT _REFERENCES(comp, WNDS, RNPS, WNPS);
END finanzas;
/
CREATE PACKAGE BODY finanzas AS
FUNCTION comp
(anos IN NUMBER
cant
IN NUMBER
porc
IN NUMBER) RETURN NUMBER IS
BEGIN comp
RETURN cant * POWER((porc/100) +1, anos)
END comp;
END finanzas;
/
Dep. Informtica
36
PL/SQL
2.5.- VENTAJAS DE PROCEDIMIENTOS, FUNCIONES Y [Link] uso de procedimientos, funciones de usuario y paquetes presenta una serie de ventajas:
Fcil mantenimiento
- Permite modificar procedimientos on-line sin interferir al resto de los usuarios (que
ejecutan una versin anterior).
- La modificacin de una rutina afecta a todas las aplicaciones que trabajen con ella.
Esto implica eliminar la duplicidad de las comprobaciones.
2.6.- MANEJO DE [Link] procedimientos y funciones deben prever cualquier tipo de excepcin ocurrida mientras
se ejecutan, bien propagando el error al entorno de llamada o bien desvindolo a una zona del
subprograma.
Como sabemos hay dos tipos de exepciones: las de Oracle y las definidas por el usuario. La
siguiente tabla muestra como conseguir la comunicacin interactiva del error o realizar una
operacin en la base de datos.
Tipo de excepcin
Efecto a conseguir
Mtodo de manejo
Dep. Informtica
37
PL/SQL
Las excepciones de Oracle pueden ser controladas por el usuario con la sentencia
EXCEPTION_INIT ya vista, que permite comunicar el cdigo y el mensaje de error para una
excepcin de Oracle de forma interactiva omitiendo el manejo de excepciones.
Si se omite el manejo de errores y el procedimiento termina con un fallo, devolver al entorno
de llamada el error "UNHANDLED EXCEPTION".
Ejemplo: Propagar una excepcin del Servidor Oracle (usando la base de datos de ejemplo
de oracle)
Dep. Informtica
38
PL/SQL
Ejemplo: Desviar el flujo del programa a una excepcin Oracle predefinida. (usando la
base de datos de ejemplo de oracle)
Dep. Informtica
39
PL/SQL
Para direccionar el flujo de programa a una excepcin Oracle no predefinida, invocndola con
la sentencia EXCEPTION_INIT hay que seguir los siguientes pasos:
-
Declarar la excepcin.
Asociar la excepcin declarada con un nmero de error Oracle utilizando la sentencia
EXCEPTION_INIT.
2.7.- EJERCICIOS.2.7.1.- Ejercicios resueltos.1.- Crear el procedimiento aumento_salario para aumentar el salario de un empleado en una
cantidad. El nmero de empleado y el aumento se le pasarn a la funcin, la cual deber
controlar los errores producidos por la inexistencia del empleado y del salario (valor nulo).
Dep. Informtica
40
PL/SQL
/
3.- Ejemplo completo de paquete:
Consideremos el siguiente paquete emp_actions. La parte de especificacin del paquete
declara los siguientes tipos de datos, variables y subprogramas:
Tras la escritura del paquete, podemos escribir subprogramas que hagan referencia a los tipos
que declara, a su cursor y a su excepcin, por que el paquete se almacena en la base de datos
para uso pblico.
Dep. Informtica
41
PL/SQL
ename VARCHAR2,
job VARCHAR2,
mgr REAL,
sal REAL,
comm REAL,
deptno REAL) RETURN INT IS
new_empno INT;
BEGIN
SELECT empno_seq.NEXTVAL INTO new_empno FROM dual;
INSERT INTO emp VALUES (new_empno, ename, job,
mgr, SYSDATE, sal, comm, deptno);
number_hired := number_hired + 1;
RETURN new_empno;
END hire_employee;
PROCEDURE fire_employee (emp_id INT) IS
BEGIN
DELETE FROM emp WHERE empno = emp_id;
END fire_employee;
/* Definiciones locales de funciones accesibles solo desde este paquete. */
FUNCTION sal_ok (rank INT, salary REAL) RETURN BOOLEAN IS
min_sal REAL;
max_sal REAL;
BEGIN
SELECT losal, hisal INTO min_sal, max_sal FROM salgrade
WHERE grade = rank;
RETURN (salary >= min_sal) AND (salary <= max_sal);
END sal_ok;
PROCEDURE raise_salary (emp_id INT, grade INT, amount REAL) IS
salary REAL;
BEGIN
SELECT sal INTO salary FROM emp WHERE empno = emp_id;
IF sal_ok(grade, salary + amount) THEN
Dep. Informtica
42
PL/SQL
horas
NUMBER,
minutos
NUMBER);
TYPE TransRec IS RECORD (
categoria
VARCHAR2,
cuenta
NUMBER,
cantidad
NUMBER,
horario
TimeRec);
minimo_balance
CONSTANT NUMBER := 10.00;
numero_procesado
NUMBER;
insuficiente_saldo
EXCEPTION;
END trans_data;
Este paquete no tiene ningn cuerpo, porque los registros, variables, constantes y excepciones
no tienen ninguna implementacin especial. Se definen variables globales -utilizables por
subprogramas y disparadores de bases de datos- que persistirn durante toda la sesin.
2.7.2.- Ejercicios propuestos.1.- Crear el procedimiento ALTA_DEP, que permitir dar de alta un nuevo departamento en
la tabla TDEPTO. Por defecto pondr el campo tidir a 'F' y el campo presu a cero. El
procedimiento deber controlar que:
- El director existe como empleado, si no dar el error: -20001, 'El jefe no es empleado'.
- El centro de trabajo existe, si no dar el error: -20002, 'El centro de trabajo no existe'.
- El departamento no est previamente creado, si lo estuviera dar el error: -20003,
'Departamento ya creado'.
2.- Crear la funcin SUELDO_EMP, que recibir el nmero de un empleado y devolver su
sueldo total (salario+comisin). Si el empleado suministrado no existe, devolver el error 20222 'Empleado inexistente'.
Dep. Informtica
43
PL/SQL
3.- Crear la funcin SUELDO_DEP, que haciendo uso de la funcin anterior, reciba un
nmero de departamento y devuelva el sueldo total que cobran sus empleados. Si el
departamento suministrado no existe devolver el error: -20223, 'Departamento inexistente'.
4.- Disear el procedimiento AUMENTO_SALARIO, que reciba un nmero de departamento
y un porcentaje, realice el incremento de los salarios de los empleados de ese departamento en
el porcentaje dado. Si no se especifica porcentaje, se supondr del 0,5%. Si el departamento
suministrado no existe devolver el error: -20223, 'Departamento inexistente'.
5.- Crear el paquete PAQ_EMPLE que recoja todos los procedimientos y funciones
desarrollados (alta_emp, baja_emp, consulta_emp, sueldo_emp y aumento_salario).
Dep. Informtica
44
PL/SQL
3.1.- DISPARADORES.3.1.1.- [Link] permite definir procedimientos almacenados en la base de datos, que estn
asociados a una tabla y que son ejecutados implcitamente ("disparados") cuando una
instruccin INSERT, UPDATE o DELETE se ejecuta sobre la tabla asociada. Estos
procedimientos reciben el nombre de disparadores de la base de datos.
Un disparador puede incluir instrucciones SQL e instrucciones PL/SQL y puede invocar a
otros procedimientos. Los procedimientos y los disparadores se diferencian en la forma en
que son invocados. Mientras un procedimiento lo ejecuta explcitamente un usuario o una
aplicacin, un disparador es ejecutado (disparado) implcitamente por Oracle cuando se
ejecuta una instruccin INSERT , UPDATE o DELETE de un disparador.
La siguiente figura muestra una aplicacin de la base de datos con algunas instrucciones SQL
que implcitamente disparan varios disparadores almacenados en la base de datos.
Base de datos
Aplica
ciones
UPDATE ..SET ..
INSERT INTO ..
DELETE FROM ..
Tabla 1
----------------------------------------------
UPDATE TIGGER
BEGIN
....
INSERT TIGGER
BEGIN
....
DELETE TIGGER
BEGIN
....
Los disparadores se almacenan en la base de datos, separados de las tablas asociadas a ellos.
Dep. Informtica
45
PL/SQL
Slo se pueden definir sobre tablas, y no sobre vistas, sin embargo, los disparadores definidos
sobre la tabla o tablas base de una vista son disparados si se ejecuta sobre la vista una
instruccin INSERT, UPDATE o DELETE.
Para crear un disparador se debe usar ORACLE con la opcin de procedimiento que se activa
al ejecutar los scripts [Link] y [Link], que en la versin 10g Express
Edition se encuentran en C:\oraclexe\app\oracle\product\10.2.0\server\RDBMS\ADMIN, y
son cargados automticamente al iniciar una sesin. Si no estuvieran cargados, el
administrador debe ejecutarlos.
Tambin es necesario tener uno de los siguientes privilegios CREATE TRIGGER o CREATE
ANY TRIGGER, que permiten a un usuario crear disparadores en una tabla de su esquema, o
bien de cualquier (ANY) esquema.
Si el disparador usa instrucciones SQL o invoca a procedimientos o funciones, el usuario que
define el disparador debe tener los privilegios necesarios para utilizarlos.
3.1.2.- [Link] disparador puede crearse con el DBA Studio o el comando CREATE TRIGGER desde
alguna herramienta interactiva (como SQL*PLUS, SQL*DBA). Su sintaxis es:
CREATE [OR REPLACE] TRIGGER [Link]
{BEFORE / AFTER} { INSERT / DELETE / UPDATE [OF lista_columnas]
[ OR INSERT / DELETE / UPDATE [OF lista_columnas]
[ OR INSERT / DELETE / UPDATE [OF lista_columnas]]]}
ON [Link]
[ REFERENCING OLD [AS] antiguo [ NEW [AS] nuevo ] ]
[ FOR EACH ROW [WHEN (condicin)] ]
bloque_pl/sql
/
OR REPLACE:
esquema:
disparador:
BEFORE:
Dep. Informtica
46
PL/SQL
AFTER:
DELETE:
Indica que se dispara cuando con DELETE se borre una fila de la tabla.
INSERT:
Indica que se dispara cuando con INSERT se aada una fila en la tabla.
UPDATE OF:
ON:
bloque_Pl/sql:
ADVERTENCIAS:
1.- El comando CREATE TRIGGER debe terminar con una barra oblicua (/).
2.- Crear un disparador cuya sintaxis sea correcta no dando errores al ser compilado, no
significa que sea semnticamente correcto. De hecho, el error ms frecuente en el uso
de disparadores aparece al ejecutarlos y tratar de acceder o referenciar directa o
indirectamente con algn tipo de operacin a la misma tabla que activ el disparador,
cosa que est totalmente prohibida.
Las siguientes vistas del diccionario de datos muestran informacin sobre los disparadores:
- USER_TRIGGERS
- ALL_TRIGGERS
- DBA_TRIGGERS (vase el ejercicio resuelto 1):
Dep. Informtica
47
PL/SQL
3.1.3.- Nombres correlativos .En los disparadores de fila, existen dos nombres correlativos, OLD y NEW, para cada
columna de la tabla que se est modificando. Para referenciar a los valores nuevos de la
columna se utiliza el calificador NEW antes del nombre de la columna, y para los valores
antiguos se usa el calificador OLD.
Dependiendo del tipo de instruccin disparador puede suceder que algunos nombres
correlativos no tengan significado:
-
Un disparador disparado por una instruccin INSERT tiene acceso solamente a los valores
nuevos de la columna. Los valores viejos son NULL.
Un disparador disparado por una instruccin UPDATE tiene acceso a los valores viejos y
nuevos de la columna para los disparadores fila BEFORE y AFTER.
Un disparador disparado por una instruccin DELETE tiene acceso solamente a los
valores viejos de la columna. Los valores nuevos son NULL.
Los nombres correlativos tambin se pueden usar en el predicado de una clusula WHEN.
Cuando los calificadores NEW y OLD se usan en el cuerpo de un disparador (bloque
PL/SQL) deben ir precedidos por dos puntos (:), que no son permitidos cuando se utilizan en
la clusula WHEN o en la opcin REFERENCING OLD...
Instruccin disparador,
Restriccin disparador, y
Accin disparador.
3.2.1.- Instruccin [Link] instruccin disparador es la instruccin SQL que causa que un disparador sea ejecutado.
Puede ser una instruccin INSERT, UPDATE o DELETE para una tabla especfica. Por
ejemplo, la instruccin disparador:
UPDATE OF exis ON articulos
significa que cuando la columna exis de una fila en la tabla articulos se modifique, se ejecuta
el disparador (se dispara).
Cuando la instruccin disparador es una instruccin UPDATE se puede incluir una lista de
columnas para identificar qu columnas deben ser modificadas para que se dispare el
disparador; como las instrucciones INSERT y DELETE afectan a filas completas de la tabla,
no es necesario especificar una lista de columnas para estas opciones.
Una instruccin disparador puede contener mltiples instrucciones DML:
... INSERT OR UPDATE OR DELETE ON asegurados ...
Dep. Informtica
48
PL/SQL
Lo que significa que cuando una instruccin INSERT, UPDATE o DELETE se ejecuta sobre
la tabla asegurados, se dispara el disparador.
Cuando se utilizan mltiples tipos de instrucciones DML en un disparador, se pueden utilizar
predicados condicionales (INSERTING, DELETING, y UPDATING) para detectar qu
instruccin ha disparado el disparador. Por lo tanto, se pueden crear disparadores que ejecuten
distintos fragmentos de cdigo segn la instruccin disparador que ha disparado el disparador.
En el siguiente ejemplo se supone que la tabla tdepto tiene una nueva columna: total_sal, con
el total de salarios (no comisiones) de los empleados de ese departamento.
CREATE OR REPLACE TRIGGER total_salario
AFTER DELETE OR INSERT OR UPDATE OF numde, salar ON temple FOR EACH ROW
BEGIN
/* se asume que numde y salar son NO NULOS */
IF DELETING OR (UPDATING AND :[Link] != :[Link]) THEN
UPDATE
tdepto
SET
total_sal = total_sal - :[Link]
WHERE
numde = :[Link] ;
END IF ;
IF INSERTING OR (UPDATING AND :[Link] != :[Link]) THEN
UPDATE
tdepto
SET
total_sal = total_sal + :[Link]
WHERE
numde = :[Link] ;
END IF ;
IF (UPDATING AND :[Link] = :[Link]) THEN
UPDATE
tdepto
SET
total_sal = total_sal - :[Link] + :[Link]
WHERE
numde = :[Link] ;
END IF ;
END;
/
Ntese que si se modifica el departamento de un empleado se cumplen las dos primeras condiciones.
3.2.2.- Restriccin [Link] restriccin disparador especifica un predicado o condicin que debe ser verdadera para
que el disparador se dispare. La accin disparador no se ejecuta en caso contrario.
La restriccin disparador es una opcin disponible para los disparadores fila. Se especifica
utilizando la clusula WHEN.
3.2.3.- Accin [Link] accin disparador es el procedimiento (bloque PL/SQL) que contiene las instrucciones
SQL y el cdigo PL/SQL que se ejecuta cuando una instruccin disparador es ejecutada y la
restriccin disparador (si existe) se evala como verdadera.
Una accin disparador puede contener instrucciones SQL y PL/SQL, puede definir elementos
del lenguaje PL/SQL (variables, constantes, cursores, excepciones, etc.), y puede llamar a
otros procedimientos.
Dep. Informtica
49
PL/SQL
3.3.- TIPOS DE [Link] las opciones BEFORE/AFTER y FOR EACH ROW, se pueden crear cuatro tipos
bsicos de disparadores. El tipo de un disparador determina:
- cundo dispara ORACLE el disparador en relacin a la instruccin disparador, y
- cuntas veces dispara ORACLE el disparador.
La siguiente tabla describe cada tipo de disparador, sus propiedades y las opciones utilizadas
para crearlos.
Opcin
BEFORE
AFTER
Para obtener valores de columnas especficos antes de ejecutar una instruccin disparador
INSERT o UPDATE.
50
PL/SQL
CREATE TRIGGER rt BEFORE UPDATE OR DELETE OR INSERT ON sal FOR EACH ROW
BEGIN
[Link] := [Link] + 1 ;
END ;
/
CREATE TRIGGER at AFTER UPDATE OR DELETE OR INSERT ON sal
DECLARE
typ CHAR(8);
hour NUMBER ;
BEGlN
IF updating THEN typ :='update' ; END IF ;
IF deleting THEN typ :='delete' ; END IF ;
IF inserting THEN typ :='insert' ; END IF ;
Hour := TRUNC( (SYSDATE- TRUNC( SYSDATE ) )*24 ) ;
UPDATE
stat_tab
SET
rowent = rowent + [Link]
WHERE
utype = typ AND uhour = hour;
IF SQL%ROWCOUNT = 0 THEN
INSERT INTO stat_tab VALUES ( typ, [Link], hour );
END IF ;
EXCEPTION
WHEN dup_val_on_index THEN
UPDATE
stat_tab
SET
rowent = rowent + [Link]
WHERE
utype = typ AND uhour = hour ;
END ;
/
3.4.- MODIFICACIN Y BORRADO DE [Link] disparador no se puede modificar explcitamente, debe reemplazarse con una nueva
definicin de disparador.
Para reemplazar un disparador en CREATE TRIGGER se incluye la opcin OR REPLACE
que permite crear una nueva versin de un disparador que ya existe en la base de datos, sin
que se vean afectados los privilegios que tena el disparador antiguo.
En caso de que en vez de usar la opcin OR REPLACE, borremos el disparador y
posteriormente lo creemos de nuevo con las modificaciones necesarias, todos los privilegios
del disparador antiguo se habrn borrado y debern volverse a otorgar al disparador nuevo.
Un disparador se puede encontrar habilitado o inhabilitado. Solo en el caso de estar
habilitado, ORACLE lo dispara siempre que se ejecuta una instruccin disparador y la
restriccin disparador (si existe) es evaluada TRUE. Cuando se crea un disparador, ORACLE
automticamente lo habilita. Es til inhabilitar temporalmente un disparador cuando:
-
Se va a cargar una gran cantidad de datos y se quiere realizar rpidamente sin que se
disparen los disparadores.
Dep. Informtica
51
PL/SQL
Para habilitar o inhabilitar disparadores usa el comando ALTER TRIGGER. Su sintaxis es:
ALTER TRIGGER disparador { ENABLE / DISABLE} ;
Otra forma es con el comando ALTER TABLE con las clusulas DISABLE y ENABLE y la
opcin ALL TRIGGERS de este comando. Ejemplo:
ALTER TABLE temple DISABLE ALL TRIGGERS
Para habilitar o inhabilitar disparadores utilizando el comando ALTER TABLE, se debe ser el
propietario de la tabla, tener el privilegio de objetos ALTER para la tabla, o tener el privilegio
del sistema ALTER ANY TABLE. Para habilitar o inhabilitar disparadores utilizando el
comando ALTER TRIGGER, se debe ser el propietario del disparador o tener el privilegio del
sistema ALTER ANY TRIGGERS.
Para borrar un disparador, ste debe estar en nuestro esquema o disponer del privilegio del
sistema DROP ANY TRIGGER. Se usa el comando DROP TRIGGER, cuya sintaxis es:
DROP TRIGGER <disparador > ;
3.5.- MANEJO DE [Link] durante la ejecucin de un disparador se produce un error predefinido en el sistema o
definido por el usuario, entonces se anulan todas las actualizaciones realizadas por la accin
disparador as como el evento que la activ.
La sentencia RAISE_APPLICATION_ERROR (num_error, 'mensaje') provoca la ocurrencia
del error de nmero interno num_error y envia al usuario el mensaje 'mensaje'. (num_error
debe ser un nmero negativo comprendido entre 20000 y 20999). Un ejemplo de su uso
puede verse en el ejercicio resuelto 2.
52
PL/SQL
TRIGGER_TYPE
TRIGGERING_EVENT TABLE_NAME
UPDATE OR DELETE
SELECT
FROM
WHERE
Rdo:
DEPT
trigger_body
user_triggers
trigger_name = 'DEP_SET_NULL' ;
TRIGGER_BODY
BEGIN
IF UPDATING AND :[Link] != :[Link] THEN
UPDATE emp SET [Link] = NULL
WHERE [Link] = :[Link] ;
END IF ;
END ;
END ;
/
ORACLE dispara el disparador siempre que una instruccin INSERT, UPDATE o DELETE
afecte a la tabla EMP del esquema SCOTT. El disparador realiza las siguientes operaciones:
1.- Si la modificacin se intenta realizar un sbado o un domingo, el
disparador no permite la modificacin y da un mensaje de error.
2.- Si la hora en que se intenta modificar no est entre las 8:00 AM y las
6:00 PM, el disparador da un mensaje de error.
Dep. Informtica
53
PL/SQL
ORACLE dispara el disparador siempre que se ejecute una de las siguientes instrucciones:
-
3.6.2.- Ejercicios propuestos.1.- Partiendo del ejercicio resuelto 2, desarrollar el disparador TR_TEMPLE para que
funcione con la tabla Temple, mejorndolo para que tambin evite las actualizaciones en los
das de fiesta. Para ello deber crearse la tabla FESTIVOS con una nica columna Fiestas
contendra las fechas de los das no laborables distintos a sbados y domingos. Lgicamente
esta tabla se actualizara anualmente.
Dep. Informtica
54
PL/SQL
2.- Crear el disparador DIR_SET_NULL, que controle que antes de borrar un empleado que
sea director ponga a nulo el campo direc del departamento o departamentos de los que era
director, y que si se modifica la clave primaria de un director, actualice automticamente el
campo direc de los departamentos en los que l es director.
5.- Crear el disparador DIRPRO que evite que un director lo sea en propiedad en ms de un
departamento. Ojo, problema de las tablas mutantes.
Caso de que se intente violar la anterior restriccin, el disparador devolver el cdigo de error
-20800, y el mensaje 'El jefe ya lo es en propiedad de otro departamento.'
6.- Modificar el disparador VALIDA_SALARIO del ejercicio resuelto n 3 para que vele por
que se cumpla que los salarios de todos los empleados salvo el presidente:
- Se encuentren comprendidos entre el valor de minsal y maxsal de su categora (JOB).
- Que no disminuyan.
- Que no se vean incrementados en ms del 10 % de una vez.
El tratamiento de los errores se har con RAISE_APPLICATION_ERROR.
Dep. Informtica
55