Está en la página 1de 60

I.E.S.

TRASSIERRA
Crdoba
http://www.iestrassierra.com

Departamento de Informtica

APUNTES DE PL/SQL
Etapa: Formacin Profesional Especfica.
Ciclo: Desarrollo de Aplicaciones Informticas.
Nivel: Superior.
Mdulo: Desarrollo de Aplicaciones en Lenguajes de 4 Generacin y
con Herramientas CASE.
Profesor: Juan Carlos Prez Jorge jcperez@iestrassierra.com

INDICE:
Tema 1.- PL/SQL ................................................................................................ 1
Tema 2.- Disparadores (Triggers) ................................................................. 28
Tema 3.- Procedimientos, Funciones y Paquetes .......................................... 39
I.E.S. TRASSIERRA - Crdoba PL/SQL

TEMA 1.- PL/SQL.-


1.1.- Introduccin.
1.2.- El bloque PL/SQL.
1.3.- Tipos de datos, conversiones, mbito y visibilidad.
1.4.- Zona de declaraciones: DECLARE.
1.4.1.- Declaracin de variables y constantes.
1.4.2.- Declaracin de registros.
1.4.3.- Declaracin de cursores.
1.4.4.- Declaracin de excepciones.
1.5.- Zona de proceso: BEGIN.
1.5.1.- Sentencias propias de PL/SQL.
1.5.2.- Sentencias DML.
1.5.3.- Sentencias transaccionales.
1.6.- Zona de excepciones: EXCEPTION.
1.6.1.- Control de errores.
1.6.2.- Excepciones predefinidas.
1.6.3.- Excepciones definidas por el usuario
1.6.4.- Ejecucin de excepciones: RAISE
1.6.5.- SQLCODE.-
1.6.6.- SQLERRM.-
1.6.7.- Algunos ejemplos de tratamiento de excepciones.-
1.7.- Ejercicios.
1.7.1.- Ejercicios resueltos.
1.7.2.- Ejercicios propuestos.

1.1.- INTRODUCCIN.-
PL/SQL es un lenguaje de programacin procedural estructurado en bloques que ampla el
lenguaje estndar SQL, uniendo la potencia de ste, con la capacidad de los lenguajes de
programacin tradicionales. De esta forma, PL/SQL no slo nos permite manipular los datos
de la base de datos ORACLE, sino que dispone de tcnicas procedurales como los bucles o el
control condicional.

Una de las mayores limitaciones del SQL es la imposibilidad de tratar de forma independiente
las filas devueltas por una consulta. Esto se consigue con PL/SQL mediante el uso de cursores
que ORACLE abre para ejecutar una sentencia SELECT.

Tambin nos permite controlar los errores que se pudieran producir (excepciones), como por
ejemplo que una consulta no devuelva filas. Existen errores propios de Oracle (excepciones
predefinidas) y errores que puede provocar y definir el usuario.

El motor PL/SQL se encuentra en el Ncleo de Oracle (RDBMS)

Prof: Juan Carlos Prez Jorge 1


I.E.S. TRASSIERRA - Crdoba PL/SQL

Por extensin al SQL, PL/SQL puede acceder a la base de Datos ORACLE porque soporta:

Sentencias LMD de SQL (SELECT, INSERT, UPDATE, DELETE)


Sentencias transaccionales (COMMIT, ROLLBACK, SAVEPOINT)
Todas las funciones SQL (numricas, de caracteres, de fechas, de grupos...)
Todos los tipos de predicados (sentencia WHERE)
Las propias sentencias de PL/SQL.

Adems de la capacidad procedural, el soporte a SQL, y la integracin con Oracle ya


comentadas, PL/SQL presenta las siguientes ventajas:

Mejora del rendimiento.


Sin PL/SQL, Oracle tendra que procesar las instrucciones una a una. Cada llamada
producira un overhead1 considerable, sobre todo si consideramos que estas consultas
viajan a travs de la red. Por el contrario, con PL/SQL, un bloque completo de
sentencias puede ser enviado de una vez, lo que reduce la comunicacin con la base de
datos. Los procedimientos almacenados son compilados una vez y almacenados en la
base en formato ejecutable, consiguindose mayor rapidez y eficiencia en las
llamadas. Adems, ya que los procedimientos almacenados se ejecutan en el propio
servidor, el trfico por la red se reduce a la simple llamada y el envo de los
parmetros necesarios para su ejecucin. El cdigo ejecutable se almacena en cach y
se comparte con todos los usuarios, lo que reduce los requerimientos de memoria y
disminuye el overhead.

Portabilidad.
Las aplicaciones escritas con PL/SQL son portables a cualquier sistema operativo y
plataforma en la cual se encuentre corriendo Oracle. En otras palabras, PL/SQL corre
dondequiera que se encuentre corriendo Oracle. Esto significa que se pueden codificar
libreras que podrn ser reutilizadas en otros entornos.

Seguridad.
Los procedimientos almacenados habilitan la divisin lgica entre cliente y servidor,
de forma que se previene que se manipulen los datos desde el cliente. Adems permite
a los usuarios ejecutar solo aquellos procedimientos para los cuales tengan privilegios.
1
Informacin adjuntada a un aviso de la red para garantizar un envo correcto al destino

Prof: Juan Carlos Prez Jorge 2


I.E.S. TRASSIERRA - Crdoba PL/SQL

1.2.- EL BLOQUE PL/SQL.-


PL/SQL es un lenguaje estructurado en bloques. Un bloque es un conjunto de sentencias
procedurales y SQL. Un bloque PL/SQL consta de tres zonas:

Declaraciones: donde se definen las variables, cursores y excepciones de usuario que


se necesiten.

Proceso: donde se escriben todas las sentencias ejecutables.

Excepciones: zona donde se define el control de errores.

DECLARE DECLARE
..........
Declaracin de variables y ctes ; BEGIN
Declaracin de cursores ; ....
Declaracin de excepciones ; DECLARE
BEGIN
BEGIN ....
Sentencias ejecutables ; EXCEPTION
....
EXCEPTION END ;
Control de excepciones ; .....
EXCEPTION
END ; ............
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.

1.3.- TIPOS DE DATOS, CONVERSIONES, MBITO Y VISIBILIDAD.-

1.3.1.- Tipos de datos.-

Cada 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.

Prof: Juan Carlos Prez Jorge 3


I.E.S. TRASSIERRA - Crdoba PL/SQL

Tipos de datos de PL/SQL

Number.- Numrico. PL/SQL tiene predefinidos los siguiente subtipos:

DEC
Nmeros con punto fijo con precisin mxima de 38
DECIMAL
dgitos decimales
NUMERIC
DOUBLE
Nmeros con punto flotante con precisin mxima de
PRECISION
38 dgitos decimales
FLOAT
REAL Nmeros con punto flotante con precisin mxima de
18 dgitos decimales
INTEGER
Nmeros enteros con una precisin mxima de 38
INT
dgitos
SMALLINT

Binary_integer.- binario con desbordamiento a number. Usado para almacenar


enteros con signo. PL/SQL tiene predefinidos los siguiente subtipos de
binary_integer:

NATURAL No negativo.
NATURALN No negativo, no admite nulos.
POSITIVE Positivo.
POSITIVEN Positivo, no admite nulos.
SIGNTYPE -1, 0 y 1, usado en lgica trivaluada.

Pls_integer.- binario sin desbordamiento. Es ms actualizado que su equivalente


binary_integer, el cual se mantiene por razones de compatibilidad.

Prof: Juan Carlos Prez Jorge 4


I.E.S. TRASSIERRA - Crdoba PL/SQL

Bolanos.- solo pueden tomar 3 valores TRUE, FALSE y NULL. Usados para lgica
trivaluada.

1.3.2.- Conversiones.-

Adems de las conversiones de tipo de datos realizadas explcitamente por las funciones de
conversin, cuando se hace necesario, PL/SQL puede convertir un tipo de dato a otro en
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 BIN_INT CHAR DATE LONG NUMBER PLS_INT RAW ROWID VARCHAR2

Desde
BIN_INT X X X X X
CHAR X X X X X X X X
DATE X X X
LONG X X X
NUMBER X X X X X
PLS_INT X X X X X
RAW X X X
ROWID X X
VARCHAR2 X X X X X X X X

Tabla de conversiones implcitas

1.3.3.- mbito y visibilidad.-

Dentro de un programa, las referencias a un identificador son resueltas de acuerdo a su mbito


y visibilidad. El mbito de un identificador es aquella regin de la unidad de programa
(bloque, subprograma o paquete) desde la cual se puede referenciar al identificador. La
visibilidad se refiere a las zonas en que se puede referenciar.

Los identificadores declarados en un bloque de PL/SQL se consideran locales al bloque y


globales a todos sus sub-bloques o bloques anidados. De esto se desprende que un mismo
identificador no se puede declarar 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.

Prof: Juan Carlos Prez Jorge 5


I.E.S. TRASSIERRA - Crdoba PL/SQL

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 DECLARACIONES.-


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

La palabra reservada DECLARE, determina el comienzo de un bloque PL/SQL. Las


definiciones realizadas en esta zona son declaraciones locales que solo se reconocern en el
bloque PL/SQL actual y en los bloques anidados que pudiese contener.

1.4.1.- Declaracin de variables y constantes.-

Las 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.

Prof: Juan Carlos Prez Jorge 6


I.E.S. TRASSIERRA - Crdoba PL/SQL

Sintaxis:
nombre_campo [CONSTANT] <tipo_de_dato /
identificador% TYPE /
identificador% ROWTYPE>
[NOT NULL]
[:= <expresin_plsql / valor_constante>];
dnde:

nombre_campo Nombre de la variable o constante.


[CONSTANT] Palabra reservada para la definicin de constantes.
tipo_de_dato Tipo de dato de la variable.
identificador%TYPE Este atributo declara la variable o constante con el mismo tipo de dato
que una variable definida anteriormente o igual que una columna de una
tabla de la base de datos.
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 Obliga a que siempre tenga valor.
expresin_plsql / valor_constante Asigna a la variable o constante el valor inicial como
resultado de una operacin (expresin pl/sql) o con un valor constante.

Ejemplos:
n_dept tdepto.numde%TYPE ;
total number(10,2):=0 ;
respuesta char(1) ;
var2 var1%TYPE ;
registro1 scott.dept%ROWTYPE ;

1.4.2.- Declaracin de registros.-

Los registros son grupos de variables que pueden recibir la informacin de un cursor. Se
declaran segn la siguiente sintaxis:

TYPE nombre_registro IS RECORD (


campo1 tabla.columna%TYPE
campo2 tabla.columna%TYPE ) ;
....
var nombre_registro;

Ejemplo:

TYPE reg IS RECORD ( -- Declaracin del tipo reg


empleado temple.nomem%TYPE
salario temple.salar% TYPE ) ;
r_empleado reg; -- Declaracin de una variable de tipo reg

Prof: Juan Carlos Prez Jorge 7


I.E.S. TRASSIERRA - Crdoba PL/SQL

1.4.3.- Declaracin de cursores.-

La 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 departa IS
SELECT tdepto.numde, tdepto.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.

Prof: Juan Carlos Prez Jorge 8


I.E.S. TRASSIERRA - Crdoba PL/SQL

Ejemplo:
ACCEPT valor PROMPT Departamento:
DECLARE
CURSOR empleados (dept_pl NUMBER) IS
SELECT emp.emp_no, emp.ename
FROM emp
WHERE emp.dept_no = dept_pl ;
..........
BEGIN
OPEN empleados (&valor) ; -- Apertura del cursor y paso del parmetro

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 emp_no, ename FROM emp FOR UPDATE OF ename ;

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 -- Declaracin del tipo de cursor
....
C_emple1 CurEmp ; -- Declaracin de un cursor del tipo anterior

Dinmico prefijado

Los cursores dinmicos prefijados declaran el registro que va a recibir los datos del
cursor con RETURN <tipo_registro>.

Sintaxis: TYPE tipo_cursor IS REF CURSOR


RETURN tabla%ROWTYPE ;
...
nombre_cursor tipo_cursor ;

Ejemplo:
DECLARE
TYPE Datos IS REF CURSOR
RETURN emp%ROWTYPE ;
....
Datos.emp Datos ;

Prof: Juan Carlos Prez Jorge 9


I.E.S. TRASSIERRA - Crdoba PL/SQL

1.4.4.- Declaracin de excepciones.

Si vamos a utilizar excepciones definidas por el usuario, es necesario declararlas en la zona


DECLARE. Las excepciones de usuario se declaran simplemente escribiendo la palabra
EXCEPTION detrs del nombre asignado a la excepcin que queramos definir:

Sintaxis:
nombre_excepcin 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.

1.5.- ZONA DE PROCESO: BEGIN.-


En 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:

- Sentencias propias de PL/SQL.


- Sentencias DML de SQL (SELECT, INSERT, UPDATE, DELETE)
- Sentencias transaccionales (COMMIT, ROLLBACK, SAVEPOINT)

1.5.1.- Sentencias propias de PL/SQL.-

Las sentencias propias del lenguaje PL/SQL se agrupan en:

Asignaciones
Manejo de cursores
EXIT
Control condicional
Bucles
GOTO
NULL

1.5.1.1.- Asignacin.- La asignacin de valores a una variable se establece con el operador


":=".

Algunos ejemplos son:

salario := 2251 ;
comision := substr(cod_postal,2 ,3) ;
aumento := salario * 0.1 ;
total_sueldo := salario + aumento + comision ;

Prof: Juan Carlos Prez Jorge 10


I.E.S. TRASSIERRA - Crdoba PL/SQL

1.5.1.2.- 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 Devuelve TRUE si la ltima lectura falla porque no hay mas filas
disponibles o FALSE si recupera una fila. Se utiliza para detectar el
final y romper el bucle de lectura de un cursor.
%FOUND Es lo contrario de %NOTFOUND
%ROWCOUNT Devuelve el nmero de fila, procesada por el cursor.
%ISOPEN Devuelve TRUE si el cursor esta abierto y FALSE si esta cerrado.

Para manejar un cursor primero hay que abrirlo (OPEN), luego leerlo (FETCH) y por ltimo
cerrarlo (CLOSE).

Abrir el cursor: OPEN. La sentencia OPEN, evala la SELECT asociada al cursor y lo


prepara para permitir su lectura. La sentencia OPEN, abre el cursor y ejecuta la consulta
asociada a dicho cursor.

Tipo de cursor Sintaxis

cursor esttico simple OPEN nombre_cursor ;

cursor esttico parametrizado OPEN nombre_cursor (parm1 [,parm2] .. ) ;

cursor dinmico OPEN nombre_cursor FOR sentencia_select ;

Los parmetros se pueden pasar posicionalmente: el primer parmetro sustituye al


primero que espera el cursor y as sucesivamente, o por asociacin de nombres:

DECLARE
CURSOR departamentos (dept_pl NUMBER, loc_pl CHAR) IS
SELECT dept_no, dname, loc
FROM dept
WHERE dept_no = dept_pl and loc = loc_pl ;

BEGIN
OPEN departamentos (10, 'MADRID') ;
OPEN departamentos (v_dept, v_loc) ;
OPEN departamentos (loc_pl => 'MADRID', dept_pl => 10) ;
OPEN departamentos (loc_pl => v_loc, dept_pl => v_dept) ;

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.

Prof: Juan Carlos Prez Jorge 11


I.E.S. TRASSIERRA - Crdoba PL/SQL

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.

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
intenta realizar con un cursor que esta cerrado, provoca la excepcin predefinida
INVALID_CURSOR. Su sintaxis es:

CLOSE nombre_cursor ;

Ejemplo: CLOSE curdep;

1.5.1.3.- EXIT.-
EXIT nos permite salir de un bucle de forma radical o evaluando una condicin. Su sintaxis
es:
EXIT [nombre_bucle] [WHEN condicin] ;

Si se omite el nombre del bucle sale del bucle actual. Si se especifica WHEN, solo sale si se
cumple la condicin. Si se omiten ambos, sale del bucle actual incondicionalmente.

Prof: Juan Carlos Prez Jorge 12


I.E.S. TRASSIERRA - Crdoba PL/SQL

1.5.1.4.- Control condicional.


Permite ejecutar una o varias sentencias dependiendo de una condicin. Su sintaxis es:

IF condicin THEN sentencias ;


[ELSIF condicin THEN sentencias ;]
[ELSE sentencias ;]
END IF ;

La condicin puede ser cualquier expresin PL/SQL de comparacin.

Al procesar la sentencia, se evalan una a una todas las condiciones por orden empezando por
la que le sigue a la palabra IF. Si alguna de las condiciones se cumple, se ejecutan las
sentencias especificadas y se pasa a la siguiente instruccin tras END IF .

Si no se cumple ninguna condicin, pero existe un ELSE, se ejecutan las sentencias siguientes
al ELSE, si no es as, no se ejecuta ninguna sentencia.

Slo una secuencia de sentencias se ejecuta al procesar una instruccin IF.

Ejemplos: IF tipo = 1 THEN sal := sal * 0.01 ;


ELSIF tipo = 2 THEN sal ;= sal * 0.02 ;
ELSE sal := sal * 0.03 ;
END IF ;

1.5.1.5.- Bucles. Existen 5 tipos de bucles:

Bucles bsicos
Bucles condicionales (WHILE)
Bucles numricos (FOR)
Bucles sobre cursores
Bucles para una SELECT

Bucles Bsicos. Son bucles infinitos que responden a la siguiente sintaxis:

LOOP
sentencias ;
END LOOP ;

Para romper el bucle (salir de l) deberemos utilizar EXIT, GOTO o RAISE.

Ejemplo:
LOOP
FETCH cursor_cl INTO registro ;
EXIT WHEN cursor_cl%NOTFOUND ;
END LOOP ;

Bucles Condicionales (WHILE). La condicin se evala antes de cada entrada al bucle.


Si la condicin se cumple se ejecutan las sentencias, y si no es as, se pasa el control a la
sentencia siguiente al final del bucle. Su sintaxis es:

Prof: Juan Carlos Prez Jorge 13


I.E.S. TRASSIERRA - Crdoba PL/SQL

WHILE condicin
LOOP
sentencias;
END LOOP;

Ejemplo:
WHILE 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 es la variable numrica de control del bucle, comienza con el valor de


exp_n1 y se va incrementando de 1 en 1 hasta el valor de exp_n2.
REVERSE realiza la cuenta al revs, desde exp_n2 hasta exp_n1.
exp_n1, exp_n2 pueden ser valores constantes o cualquier expresin numrica.

Ejemplo:
FOR x IN 1 .. 10
LOOP
valor:= valor + x ;
END LOOP ;

Bucles sobre Cursores. Son bucles que se ejecutan para cada fila que recupera el 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.

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.

Prof: Juan Carlos Prez Jorge 14


I.E.S. TRASSIERRA - Crdoba PL/SQL

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 un 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.

Sintaxis:
FOR nombre_registro IN sentencia_SELECT
LOOP
sentencias ;
END LOOP ;

Si se sale del bucle prematuramente, o se detecta un error (excepcin), el cursor se cierra.


Es importante resaltar que las columnas del cursor no pueden ser usadas con
<registro.columna> fuera de estos dos ltimos bucles, ya que cierran automticamente el
cursor que tratan.

Ejemplo:
FOR registro IN SELECT dept_no FROM dept
LOOP
sentencias ;
END LOOP ;

1.5.1.6.- 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>>

Prof: Juan Carlos Prez Jorge 15


I.E.S. TRASSIERRA - Crdoba PL/SQL

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.

1.5.1.7.- 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 sal := sal * 0.01
ELSE NULL;
END IF;

1.5.2. Sentencias DML

Oracle abre un cursor implcito (no definido por el usuario) por cada sentencia SQL que tenga
que procesar. PL/SQL nos permite referimos al cursor implcito mas reciente como "SQL%".
Estos cursores los maneja Oracle, por lo que no se pueden abrir, leer o cerrar, pero si podemos
utilizar algunos atributos que nos dan informacin sobre la ejecucin de la sentencia SQL
(INSERT, UPDATE, DELETE, SELECT) para la que se haya abierto. Estos atributos son:

%NOTFOUND Devuelve TRUE si un INSERT, UPDATE o DELETE no ha procesado


ninguna fila o si la SELECT no recupera nada. En este ltimo caso se
provoca la excepcin predefinida NO_DATA_FOUND
%FOUND Devuelve TRUE si un INSERT, UPDATE o DELETE ha procesado alguna
fila o una SELECT recupera datos
%ROWCOUNT Devuelve el nmero de filas procesadas por un INSERT, UPDATE o
DELETE o las recuperadas por una SELECT .

1.5.2.1.- 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).

Sintaxis:
SELECT {* / col1 [,coI2] } INTO {reg / var1 [,var2] }
FROM tabla resto_de_la_select ;

Las excepciones predefinidas ms comunes son:

Prof: Juan Carlos Prez Jorge 16


I.E.S. TRASSIERRA - Crdoba PL/SQL

A.- Si la consulta no devuelve ninguna fila:

Se produce la excepcin predefinida NO_DATA_FOUND


El error Oracle (SQLCODE) ORA-01403
El mensaje de error (SQLERRM) "no data found"
SQL%NOTFOUND es TRUE
SQL%FOUND es FALSE
SQL%ROWCOUNT es 0

B.- Si la consulta devuelve ms de una fila:

Se produce la excepcin predetinida TOO_MANY _ROWS


El error Oracle (SQLCODE) ORA-O1422
El mensaje de error (SQLEERM) 'single-row query returns more than one row"
SQL%NOTFOUND es FALSE
SQL%FOUND es TRUE
SQL%ROWCOUNT es 1 (solo puede devolver 0 o 1 fila)

1.5.2.2.- 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 permite insertar una tupla indicando expresiones constantes o variables.


Sentencia_Select permite insertar varias tuplas a la vez.

Si no se inserta ninguna fila los atributos devuelven los siguientes valores:

SQL%NOTFOUND es TRUE
SQL%FOUND es FALSE
SQL%ROWCOUNT es 0

Prof: Juan Carlos Prez Jorge 17


I.E.S. TRASSIERRA - Crdoba PL/SQL

Si se dan de alta una o mas filas los atributos devuelven los siguientes valores:

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;

1.5.2.3.- UPDATE

La sentencia UPDA TE permite modificar los datos almacenados en las tablas o vistas.

Sintaxis:
UPDATE tabla
SET 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 de 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

Prof: Juan Carlos Prez Jorge 18


I.E.S. TRASSIERRA - Crdoba PL/SQL

Ejemplo:
UPDATE emp
SET sal = sal * 0.1 WHERE dept_no = 10 ;

1.5.2.4.- DELETE.

La sentencia DELETE permite borrar filas de la tabla o vista especificada.

Sintaxis:
DELETE [ FROM] tabla
[ WHERE {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 FROM emp
WHERE dept_no = 10;

1.5.3. Sentencias transaccionales

Como sabemos, una transaccin o Unidad Lgica de Trabajo (ULT) es una secuencia de
operaciones de actualizacin que forman un todo, de forma que o se ejecutan todas o no se
ejecuta ninguna, debiendo dejar la base de datos en estado coherente.

Una transaccin comienza en la primera sentencia SQL tras: una sentencia COMMIT, una
sentencia ROLLBACK o una conexin a la base de datos.

Una transaccin termina con: una sentencia COMMIT, una sentencia ROLLBACK o una
desconexin, intencionada o no, a la base de datos. El SGBD realiza un COMMIT implcito
antes de ejecutar cualquier sentencia de LDD (create, alter, ..) o al realizar una desconexin
que no haya sido precedida de un error.

Las sentencias SQL que permiten gestionar explcitamente las transacciones son:

Prof: Juan Carlos Prez Jorge 19


I.E.S. TRASSIERRA - Crdoba PL/SQL

o SAVEPOINT
o COMMIT
o ROLLBACK
o SET TRANSACTION READ ONLY

1.5.3.1.- SAVEPOINT.

Los puntos de salvaguarda son marcas que va poniendo el usuario durante la transaccin.
Estas marcas permiten deshacer los cambios por partes en vez de deshacer toda la transaccin.

Sintaxis: SAVEPOINT <punto_de_salvaguarda> ;

Los nombres de los puntos de salvaguarda pueden reutilizarse durante la transaccin. Al


reutilizarlo el anterior punto se pierde.

Al ejecutar un ROLLBACK sin parmetros o un COMMIT, se eliminan todos los puntos de


salvaguarda. ROLLBACK TO <punto_de_salvaguarda> hace que solo se borren los puntos
posteriores al indicado. As, por ejemplo:

INSERT INTO ...


SAVEPOINT A;
DELETE ...
ROLLBACK TO SAVEPOINT A;

deshace solo el borrado, permaneciendo pendiente la insercin realizada con INSERT .

1.5.3.2.- COMMIT.

Seala el final de una transaccin y el principio de otra indicndole al sistema que se deben
validar los cambios que se produjeron desde el principio de la transaccin que se da por
concluida, hacindolos visibles para los dems usuarios. Su sintaxis es:

COMMIT [WORK] ;

La palabra reservada WORK es opcional, y no tiene ninguna trascendencia.

Al hacer un COMMIT, se liberan todos los SAVEPOINT indicados hasta el momento.

Si se hace el COMMIT cuando tenemos abierto un cursor declarado con la opcin FOR
UPDATE OF, el siguiente FETCH provoca un error, por lo que se debe cerrar el cursor.

1.5.3.3.- ROLLBACK.

Seala el final de una transaccin y el principio de otra indicndole al sistema que se deben
restaurar el estado de la base de datos tal y como estaba al comenzar la transaccin, es decir,
deshace todos los cambios pendientes de validacin de la transaccin actual. Su sintaxis es:

ROLLBACK [WORK] [TO SAVEPOINT punto_salvaguarda] ;

WORK es opcional, y no tiene ninguna trascendencia.

Prof: Juan Carlos Prez Jorge 20


I.E.S. TRASSIERRA - Crdoba PL/SQL

TO SAVEPOINT punto_salvaguarda deshace slo los cambios efectuados desde el punto de


salvaguarda indicado.

1.5.3.4.- SET TRANSACTION READ ONLY.

Permite establecer una transaccin de solo lectura

Sintaxis: SET TRANSACTION READ ONLY ;

Una vez especificado este comando, las siguientes consultas que se realicen, solo vern los
cambios efectuados antes de que comenzase la transaccin.

SQL*Plus dispone de un comando para controlar las validaciones de forma automtica. Su


sintaxis es:
SET AUTOCOMMIT ON/OFF

Si se especifica ON los cambios se validarn automticamente despus de cada operacin de


actualizacin de datos. La opcin por defecto es OFF y permite que sea el usuario el que
controle la validacin de los cambios con los comandos anteriores.

Las sentencias del LMD y la desconexin de Oracle llevan implcita una validacin (commit).
Si se produce la cada del sistema o la terminacin anormal de una aplicacin, se llevar a
cabo una restauracin automtica, mediante la consulta al fichero diario o log.

Oracle almacena temporalmente, en los llamados segmentos de rollback, la informacin


necesaria para deshacer los cambios si se ejecuta un ROLLBACK y dejar la informacin en
estado consistente.

Puede comprobarse que el propietario de la tabla modificada, tiene constancia al instante de


las modificaciones que se produzcan. Bastar hacer una consulta y observar el nuevo valor.

El DBA Studio es una herramienta del Administrador de la Base de Datos, por lo que al abrir
una tabla nos da la visin que de la misma tiene aqul. Si accedemos a una tabla con el DBA
Studio, no apreciaremos los cambios hasta que se cierre la sesin del usuario (nos conectemos
como otro usuario o salgamos de SQL, por ejemplo), o se ejecute el comando COMMIT.

1.6.- ZONA DE EXCEPCIONES: EXCEPTION.-


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

Prof: Juan Carlos Prez Jorge 21


I.E.S. TRASSIERRA - Crdoba PL/SQL

Slo se activa un error de todos los definidos en dicha zona.

La zona EXCEPTION termina cuando se detecta la palabra reservada END (fin de la zona y
fin del bloque PL/SQL).

La ejecucin de las sentencias asignadas a un error se producen:

Automticamente Oracle detecta un error, para el proceso y pasa el control a la zona


EXCEPTION, buscando si existe tratamiento a la excepcin del error
detectado.
Manualmente En el proceso llega un punto en el que nos interesa realizar lo mismo que
si se hubiese detectado un error y ejecutamos la excepcin.

La zona EXCEPTION es opcional y se puede omitir. En este caso, si se detecta algn error, el
bloque PL/SQL termina incorrectamente, terminando el proceso y devolviendo el control al
punto de partida.

Existen dos variables para poder recuperar los errores Oracle que se pueden producir:
SQLCODE y SQLERRM.

1.6.1.- Control de errores.

Cuando en el proceso se detecta un error, el proceso se para, pasando el control a la zona


EXCEPTION.

Sintaxis: WHEN nombre_excepcin THEN sentencias ;

nombre_excepcin es el nombre de la que se quiere controlar (predefinida o de usuario).


sentencias es el conjunto de sentencias que se ejecutan si se produce el error.

1.6.2.- Excepciones predefinidas.

En Oracle existen las siguientes excepciones predefinidas:

Nombre de excepcin Tipo de error indicado SQLCODE


CURSOR_ALREADY_OPEN Cursor abierto previamente -6511
DUP_VAL_ON_INDEX Valor duplicado en ndice -1
INVALID_CURSOR Cursor no vlido -1001
INVALID_NUMBER Nmero no vlido -1722
LOGIN_DENIED Denegada la conexin a Oracle -1017
NO_DATA_FOUND La consulta no recupera ninguna fila +100
NOT_LOGGED_ON No conectado a Oracle -1012
PROGRAM_ERROR Problema interno -6501
STORAGE_ERROR Fuera de memoria o error de memoria -6500
TIMEOUT_ON_RESOURCE Exceso de recursos consumidos -51
TOO_MANY_ROWS La consulta devuelve ms de una fila -1422
VALUE_ERROR Valor incorrecto -6502
ZERO_DIVIDE Divisin por cero -1476
OTHERS Cualquier otro error no especificado

Prof: Juan Carlos Prez Jorge 22


I.E.S. TRASSIERRA - Crdoba PL/SQL

1.6.3.- Excepciones definidas por el usuario

Existen dos tipos de excepciones a definir por los usuarios y son:

Basadas en errores ORACLE (EXCEPTION INIT).-

Asigna un nombre a un error ORACLE existente.

Sintaxis: PRAGMA EXCEPTION_INIT (nombre_excepcin, -nmero_error)

nombre_excepcin Deber estar definida como excepcin de usuario.


nmero_error Es el numero del error Oracle que se desea controlar (el que nos
devuelve el SQLCODE).

La definicin se realiza en la zona del DECLARE y el control de la excepcin en la zona


EXCEPTION. Solo debe haber una excepcin por cada error Oracle.

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;

1.6.4. - Ejecucin de excepciones: RAISE

Para la ejecucin del bloque PL/SQL y pasa el control a la zona de excepciones.

Sintaxis: RAISE nombre_excepcin

El nombre_excepcin es el nombre de la excepcin que se desea ejecutar, pueden ser


excepciones predefinidas o excepciones de usuario.

Ejemplo: DECLARE
error EXCEPTION;
BEGIN
RAISE error;
RAISE TOO_MANY _ROWS;
EXCEPTION
WHEN error THEN ...;
WHEN TOO_MANY _ROWS THEN ... ;
END;

Prof: Juan Carlos Prez Jorge 23


I.E.S. TRASSIERRA - Crdoba PL/SQL

1.6.5.- SQLCODE.-

La 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.

1.6.6.- SQLERRM.-

La 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.

1.6.7.- Algunos ejemplos de tratamiento de excepciones.-

1.- Excepciones predefinidas.


EXCEPTION
WHEN zero_divide THEN
Rollback;
WHEN value_error THEN
INSERT INTO errores VALUES
Commit;
WHEN others THEN
NULL;
END;

2.- Excepcin de usuario.


DECLARE
emp_sal temple.salar%TYPE;
emp_no temple.numem%TYPE;
salario_muy_alto EXCEPTION;
BEGIN
SELECT numem, salar INTO emp_no, emp_sal
FROM temple WHERE nomem = 'DURAN, LIVIA';

IF emp_sal * 1.05 > 4000 THEN


RAISE salario_muy_alto
ELSE
UPDATE temple SET.....
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
WHEN salario_muy_alto THEN
INSERT INTO emp_alto_sal VALUES(emp_no);
COMMIT;
END;

Prof: Juan Carlos Prez Jorge 24


I.E.S. TRASSIERRA - Crdoba PL/SQL

3.- Cualquier error se graba en el fichero errores.


DECLARE
err_num NUMBER;
err_msg VARCHAR2(100);
BEGIN

EXCEPTION
WHEN OTHERS THEN
err_num := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 100);
INSERT INTO errores VALUES(err_num, err_msg);
END;

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 -- Parametro de entorno que activa el buffer de salida y le
-- asigna un tamao de 5000 bytes.
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'); -- Envio al buffer del literal
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 ;

Prof: Juan Carlos Prez Jorge 25


I.E.S. TRASSIERRA - Crdoba PL/SQL

2.- Idem al anterior, pero usando un bucle WHILE.


DROP TABLE temporal ;
CREATE TABLE temporal (numero number(2));
DECLARE
i number(2):=1;
BEGIN
WHILE i < 15 LOOP
INSERT INTO temporal VALUES (i);
i:=i+1;
END LOOP;
END;
/
SELECT * FROM temporal ;

3.- Idem al anterior, pero usando un bucle FOR.

DROP TABLE temporal ;


CREATE TABLE temporal (numero number(2));
DECLARE
i number(2):=1;
BEGIN
FOR I IN 1 .. 14 LOOP
INSERT INTO temporal VALUES (i);
END LOOP;
END;
/
SELECT * FROM temporal ;

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;

Prof: Juan Carlos Prez Jorge 26


I.E.S. TRASSIERRA - Crdoba PL/SQL

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.

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)
Realizar el ejercicio utilizando un bucle simple y tratando el cursor.

5.- Modificar el programa anterior para que en la tabla TOTALES no se inserten los
departamentos inexistentes.

6.- Realizar el mismo ejercicio con un bucle sobre el cursor.

7.- Crear un procedimiento que compruebe que el formato de una fecha es correcto. En caso
contrario guardar el error en la tabla f_error que deber estar creada con la siguiente
estructura:
fecha char(8)
error number
mensaje char(80)
Si se produce otro tipo de error tambin se guardar en la misma tabla.

8.- A partir de las tablas tdepto y temple, realizar los aumentos de sueldo (columna salar)
siguientes:
tdepto.nomde % subida
FINANZAS 10
PERSONAL 20
RESTO 5

Adems, crear la tabla T-DEP, que contendr, por cada departamento, el nmero de
empleados con comisin y sin comisin, y con la siguiente estructura:
deptno number(3)
sin_comm number(3)
con_comm number(3)

Controlar el error de Oracle 'dup_val_on_index' insertando un registro en la tabla errores con


el formato siguiente:
codigo char(10)
mens char(100)

9.- Idem al ejercicio anterior, pero si se produce duplicidad de ndices, se acumularn los
valores de empleados con comisin y sin comisin al departamento correspondiente de la
tabla T_DEP, y cualquier otro error se registrar en la tabla errores.

Prof: Juan Carlos Prez Jorge 27


I.E.S. TRASSIERRA - Crdoba PL/SQL

TEMA 2.- DISPARADORES (TRIGGERS)


2.1.- Disparadores.
2.1.1.- Concepto.
2.1.2.- Sintaxis.
2.1.3.- Nombres correlativos.
2.2.- Componentes de un disparador.
2.2.1.- Instruccin.
2.2.2.- Restriccin.
2.2.3.- Accin.
2.3.- Tipos de disparadores.
2.4.- Modificar y borrar disparadores.
2.5.- Manejo de errores.
2.6.-Ejercicios.
2.6.1.- Ejercicios resueltos.
2.6.2.- Ejercicios propuestos.

2.1.- DISPARADORES .-

2.1.1.- Concepto.-

ORACLE 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 Tabla 1 UPDATE TIGGER

UPDATE ..SET .. ---------- BEGIN


INSERT TIGGER
....
----------
INSERT INTO .. ---------- BEGIN
.... DELETE TIGGER
----------
BEGIN
DELETE FROM .. ---------- ....

Prof: Juan Carlos Prez Jorge 28


I.E.S. TRASSIERRA - Crdoba PL/SQL

Los disparadores se almacenan en la base de datos, separados de las tablas asociadas a ellos.

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. Antes de
crear un disparador, el usuario SYS debe ejecutar los siguientes script de SQL,
DBMSSTDX.SQL y CATPROC.SQL, que en la versin Personal 8i se encuentran en
C:\ORACLE\ORA81\DRBMS\ADMIN, y son cargados automticamente al iniciar una
sesin.

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.

2.1.2.- Sintaxis.-

Un 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 esquema.disparador

{BEFORE / AFTER} { INSERT / DELETE / UPDATE [OF lista_columnas]


[ OR INSERT / DELETE / UPDATE [OF lista_columnas]
[ OR INSERT / DELETE / UPDATE [OF lista_columnas]]]}
ON esquema.tabla

[ REFERENCING OLD [AS] antiguo [ NEW [AS] nuevo ] ]

[ FOR EACH ROW [WHEN (condicin)] ]

bloque_pl/sql
/

OR REPLACE: Reemplaza el disparador si ya existe. Se usa para cambiar la definicin de


un disparador que ya exista sin tener que borrarlo antes.

esquema: Es el nombre del esquema que contiene al disparador. Si se omite, se crea


el disparador en el esquema del usuario.

disparador: Es el nombre del disparador. Ha de ser nico con respecto a otros


disparadores en el esquema, aunque no tiene porque ser nico con respecto
a otros objetos del esquema (tablas, vistas y procedimientos).

BEFORE: Indica que ORACLE dispara el disparador antes de ejecutar la instruccin


disparador (INSERT, UPDATE o DELETE).

Prof: Juan Carlos Prez Jorge 29


I.E.S. TRASSIERRA - Crdoba PL/SQL

AFTER: Indica que el disparador se dispara despus de ejecutar la instruccin


disparador (INSERT, UPDATE o DELETE).

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: Indica que se dispara el disparador siempre que con UPDATE se
modifique un valor en una de las columnas especificadas en la clusula
OF. Si se omite la clusula OF, el disparador se dispara siempre que una
instruccin UPDATE modifique un valor en alguna columna de la tabla.

ON: Especifica el esquema y nombre de tabla sobre la que se crea el disparador.


No se puede crear un disparador sobre una tabla en el esquema SYS.

REFERENCING: Especifica correlacin de nombres. Se puede usar correlacin de nombres


en los bloques PL/SQL y en la clusula WHEN de un disparador para
referenciar los valores viejos y nuevos de la fila actual. Los nombres
correlativos por defecto son OLD y NEW.

FOR EACH ROW: Designa que el disparador ser un disparador fila. ORACLE dispara un
disparador fila una vez por cada fila afectada por el disparador. Si se omite
esta clusula, el disparador ser un disparador instruccin. ORACLE
dispara un disparador instruccin slo una vez cuando la instruccin
disparador se ejecuta.

WHEN : Indica la restriccin disparador. Esta restriccin contiene una condicin


SQL que debe satisfacerse para disparar el disparador. Esta condicin debe
contener nombres correlativos y no puede contener una consulta. Solo
puede especificarse una restriccin para un disparador fila. La condicin se
evala para cada fila que se vea afectada por la instruccin disparador.

bloque_Pl/sql: Es el bloque PL/SQL que ORACLE ejecuta cuando dispara el disparador.


El bloque PL/SQL de un disparador no puede contener las siguientes
instrucciones SQL: COMMIT , ROLLBACK, y SAVEPOINT.

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):

Prof: Juan Carlos Prez Jorge 30


I.E.S. TRASSIERRA - Crdoba PL/SQL

2.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...

2.2.- COMPONENTES DE UN DISPARADOR.-


Un disparador consta de tres componentes:

- Instruccin disparador,
- Restriccin disparador, y
- Accin disparador.

2.2.1.- Instruccin disparador.-

Una 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.

Prof: Juan Carlos Prez Jorge 31


I.E.S. TRASSIERRA - Crdoba PL/SQL

Una instruccin disparador puede contener mltiples instrucciones DML:

... INSERT OR UPDATE OR DELETE ON asegurados ...

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 :old.numde != :new.numde) THEN
UPDATE tdepto
SET total_sal = total_sal - :old.salar
WHERE numde = :old.numde ;
END IF ;

IF INSERTING OR (UPDATING AND :old.numde != :new.numde) THEN


UPDATE tdepto
SET total_sal = total_sal + :new.salar
WHERE numde = :new.numde ;
END IF ;

IF (UPDATING AND :old.numde = :new.numde) THEN


UPDATE tdepto
SET total_sal = total_sal - :old.salar + :new.salar
WHERE numde = :new.numde ;
END IF ;
END;
/

Ntese que si se modifica el departamento de un empleado se cumplen las dos primeras condiciones.

2.2.2.- Restriccin disparador.-

Una 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.

2.2.3.- Accin disparador.-

Una 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.

Prof: Juan Carlos Prez Jorge 32


I.E.S. TRASSIERRA - Crdoba PL/SQL

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.

2.3.- TIPOS DE DISPARADORES.-


Usando 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.

FOR EACH STATEMENT FOR EACH ROW


Opcin ( Instruccin) (Fila)
La accin disparador se ejecuta antes de
La accin disparador se ejecuta antes
BEFORE modificar cada fila afectada por la
de ejecutar la instruccin disparador.
instruccin disparador.

La accin disparador se ejecuta La accin disparador se ejecuta despus


AFTER despus de ejecutar la actualizacin de modificar cada fila afectada por la
(instruccin disparador). instruccin disparador.

Los disparadores de tipo BEFORE se usan normalmente en las siguientes situaciones:

- Cuando la accin disparador debe determinar si se ejecuta o no la instruccin disparador.

- Para obtener valores de columnas especficos antes de ejecutar una instruccin disparador
INSERT o UPDATE.

Los disparadores de tipo AFTER se usan normalmente en las siguientes situaciones:

- Cuando se quiere que la instruccin disparador termine su ejecucin antes de ejecutar la


accin disparador.

- Si hay definido un disparador BEFORE, se puede definir un disparador AFTER que


realice acciones diferentes sobre la misma instruccin disparador.

El siguiente ejemplo muestra distintas posibilidades de disparador. Aparece una nueva


instruccin que permite crear un paquete (objeto que permite agrupar procedimientos,
funciones y datos como una unidad y que estudiaremos en el prximo tema) de nombre stat y
que solo contiene la declaracin pblica de la variable numrica stat.rowent.

Prof: Juan Carlos Prez Jorge 33


I.E.S. TRASSIERRA - Crdoba PL/SQL

DROP TABLE stat_tab ;

CREATE TABLE Stat_tab (utype CHAR(8),


rowent INTEGER,
uhour INTEGER);

CREATE OR REPLACE PACKAGE stat IS


rowent INTEGER;
END;
/

CREATE TRIGGER bt BEFORE UPDATE OR DELETE OR INSERT ON sal


BEGIN
stat.rowent :=0;
END;
/

CREATE TIGGER rt BEFORE UPDATE OR DELETE OR INSERT ON sal FOR EACH ROW
BEGIN
stat.rowent := stat.rowent + 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 + stat.rowent
WHERE utype = typ AND uhour = hour;
IF SQL%ROWCOUNT = 0 THEN
INSERT INTO stat_tab VALUES ( typ, stat.rowent, hour );
END IF ;

EXCEPTION
WHEN dup_val_on_index THEN
UPDATE stat_tab
SET rowent = rowent + stat.rowent
WHERE utype = typ AND uhour = hour ;
END ;
/

2.4.- MODIFICACIN Y BORRADO DE DISPARADORES.-


Un disparador no se puede modificar explcitamente, debe reemplazarse con una nueva
definicin de disparador.

Para reemplazar un disparador se incluye la opcin OR REPLACE en CREATE TRIGGER


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.

Prof: Juan Carlos Prez Jorge 34


I.E.S. TRASSIERRA - Crdoba PL/SQL

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 referencia un objeto que no est disponible.


- Se va a cargar una gran cantidad de datos y se quiere realizar rpidamente sin que se
disparen los disparadores.
- Se est recargando datos.

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 se usa el comando DROP TRIGGER, cuya sintaxis es:

DROP TRIGGER <disparador > ;

Para borrar un disparador, el disparador debe estar en nuestro esquema o debemos tener el
privilegio del sistema DROP ANY TRIGGER.

2.5.- MANEJO DE ERRORES.-


Si 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.

Prof: Juan Carlos Prez Jorge 35


I.E.S. TRASSIERRA - Crdoba PL/SQL

2.6.-EJERCICIOS.-

2.6.1.- Ejercicios resueltos.-

1.- Ejemplo de uso de las tablas del diccionario de datos. La siguiente sentencia crea un
disparador llamado DEP_SET_NULL que controla que antes de borrar una fila de la tabla
DEPTo modificar la clave primaria (deptno) de DEPT, se pongan todos los valores
relacionados de la tabla EMP a NULL:
CREATE TRIGGER dep_set_null
AFTER DELETE OR UPDATE OF deptno ON dept FOR EACH ROW

BEGIN
IF DELETING OR UPDATING AND :old.deptno != :new.deptno THEN
UPDATE emp SET emp.deptno = NULL
WHERE emp.deptno = :old.deptno ;
END IF ;
END ;
/

La siguientes consultas muestran informacin sobre el disparador DEP_SET_NULL:


SELECT trigger_type, triggering_event, table_name
FROM user_triggers
WHERE trigger_name='DEP_SET_NULL' ;

Rdo: TRIGGER_TYPE TRIGGERING_EVENT TABLE_NAME .

AFTER EACH ROW UPDATE OR DELETE DEPT

SELECT trigger_body
FROM user_triggers
WHERE trigger_name = 'DEP_SET_NULL' ;

Rdo: TRIGGER_BODY .

BEGIN
IF UPDATING AND :old.deptno != :new.deptno THEN
UPDATE emp SET emp.deptno = NULL
WHERE emp.deptno = :old.deptno ;
END IF ;
END ;

El cuerpo del disparador se almacena en la tabla del diccionario en la columna trigger_body


de tipo long. Como la longitud de visualizacin de los campos long est predefinida en 80
caracteres, para ver mejor estos resultados deberamos aumentarla, bien en el men Opciones
y Entorno del editor de SQL*Plus, o mediante el comando SET LONG 4000, por ejemplo.

2.- Crear el disparador instruccin BEFORE llamado EMP_DATE_CAMBIOS en el esquema


SCOTT. El disparador controlar que las modificaciones en los registros de empleados de la
tabla EMP slo se realicen en horas y das laborables.

CREATE TRIGGER scott.emp_date_cambios


BEFORE DELETE OR INSERT OR UPDATE ON scott.emp

BEGIN /*Si hoy es sabado o domingo se devuelve un error*/


IF ( TO_CHAR( sysdate, 'DY' ) = 'SB' OR TO_CHAR( sysdate, 'DY' ) = 'DOM' )

Prof: Juan Carlos Prez Jorge 36


I.E.S. TRASSIERRA - Crdoba PL/SQL

THEN RAISE_APPLICATION_ERROR( -20501,


'No pueden actualizarse datos de empleados en fin de semana') ;
END IF;
/* Si la actualizacin no se hace entre las 8.00 y las 18.00 h, se devuelve un error */
IF ( TO_CHAR( sysdate, 'HH24' )< 8 OR TO_CHAR( sysdate, 'HH24' ) >= 18 )
THEN RAISE_APPLICATION_ERROR( -20502,
'Solo se puede actualizar datos de empleados durante las horas de trabajo') ;
END IF;
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 .

El/la alumn@ debera mejorar este disparador para que tambin evite las actualizaciones en
los das de fiesta. La validacin se hara consultando una tabla que se actualizara anualmente
y que contendra las fechas de las fiestas (das no laborables), y que deber crear el alumnado.

3.- Este ejemplo crea un disparador fila BEFORE llamado VALIDA_SALARIO en el


esquema SCOTT. El disparador garantizar que siempre que un empleado nuevo se aada a la
tabla de empleados EMP, o se modifique el salario o el tipo de trabajo de un empleado, el
salario del empleado se mantiene dentro del rango establecido en SAL_GUIDE para su
categora. La tabla SAL_GUIDE deberemos crearla:
DROP TABLE SAL_GUIDE;
CREATE TABLE SAL_GUIDE (JOB VARCHAR2(9) primary key,
MINSAL NUMBER(7,2),
MAXSAL NUMBER(7,2) ) ;
INSERT INTO SAL_GUIDE VALUES ('CLERK', 800, 1300);
INSERT INTO SAL_GUIDE VALUES ('ANALYST', 3000, 3500);
INSERT INTO SAL_GUIDE VALUES ('SALESMAN', 1250, 1600);
INSERT INTO SAL_GUIDE VALUES ('MANAGER', 2450, 2975);
INSERT INTO SAL_GUIDE VALUES ('PRESIDENT', 5000, 5500);

CREATE OR REPLACE TRIGGER scott.valida_salario BEFORE INSERT OR UPDATE OF sal, job


ON scott.emp FOR EACH ROW
DECLARE
v_minsal sal_guide.minsal%TYPE;
v_maxsal sal_guide.maxsal%TYPE;
BEGIN /* Calcula en menor y mayor salario de esa categora de la tabla SAL_GUIDE*/
SELECT minsal, maxsal
INTO v_minsal, v_maxsal
FROM sal_guide
WHERE job = :new.job;
/* Si el salario del empleado cae fuera del rango, se provoca un error*/
IF (:new.sal< v_minsal OR :new.sal > v_maxsal) THEN
RAISE_APPLICATION_ERROR( -20601,
'Salario ' ||:new.sal || ' fuera de rango de la categoria ' ||
:new.job || ' para el empleado ' || :new.ename ) ;
END IF;
END;
/

Prof: Juan Carlos Prez Jorge 37


I.E.S. TRASSIERRA - Crdoba PL/SQL

ORACLE dispara el disparador siempre que se ejecute una de las siguientes instrucciones:

- Una instruccin INSERT que aada una fila a la tabla EMP.


- Una instruccin UPDATE que modifique los valores de las columnas SAL o JOB de
la tabla EMP.

El disparador realiza la siguientes operaciones:

1.- Consulta la tabla de salarios para obtener el salario mximo y mnimo.


2.- Compara el salario del empleado con el salario mximo y mnimo.
3.- Si el salario del empleado no est dentro del rango, el disparador d un mensaje de
error y aborta la actualizacin.

2.6.2.- Ejercicios propuestos.-

1.- Crear el disparador DEP_SET_NULL en el esquema EMPRESAX, que controle que antes
de borrar una fila de la tabla TDEPTO o modificar la clave primaria (NUMDE) de TDEPTO,
se pongan a NULL todos los valores relacionados de la tabla TEMPLE.

2.- Crear el disparador DEP_DEL_CASCADE que permita que antes de borrar un


departamento se borren todos los empleados del mismo.

3.- Sobre la tabla TDEPTO del esquema EMPRESAX, codificar el disparador de nombre
TDEPTO_PRESU_SAL que impedir que el presupuesto de un departamento sea inferior a la
suma de los salarios y comisiones de los empleados de ese departamento. Si una actualizacin
intenta violar la anterior restriccin, el disparador devolver el cdigo de error nmero -20112
y el mensaje 'El presupuesto no puede ser inferior a la suma de los sueldos de sus empleados'.

4.- 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.

5.- En el esquema SCOTT/TIGER, crear el disparador before CHEQ_SALGUIDE que velar


por que se cumpla:

- Que no se borrar ninguna tupla de SAL_GUIDE si hay algn empleado con su salario
comprendido entre sus lmites. En cuyo caso se lanzar el error 20325 y un mensaje
indicativo.

- Que una actualizacin de los valores de minsal o maxsal de SAL_GUIDE no provocar


que queden empleados de esa categora con sus salarios fuera de rango, en cuyo caso se
restablecern los valores antiguos.

Prof: Juan Carlos Prez Jorge 38


I.E.S. TRASSIERRA - Crdoba PL/SQL

TEMA 3.- PROCEDIMIENTOS, FUNCIONES Y PAQUETES.-

3.1.- Introduccin.
3.2.- Procedimientos.
3.2.1.- Creacin y borrado.
3.2.2.- Tipos de argumentos: in, out, in out.
3.2.3.- Polimorfismo.
3.3.- Funciones.
3.3.1.- Creacin y borrado.
3.3.2.- Recursividad.
3.3.3.- Funciones PL/SQL en sentencias SQL.
3.4.- Paquetes.
3.4.1.- Creacin y borrado.
3.4.2.- La depuracin
3.5.- Ventajas de los procedimientos, funciones y paquetes.
3.6.- Manejo de excepciones.
3.7.- Ejercicios.
3.7.1.- Ejercicios resueltos.
3.7.2.- Ejercicios propuestos.

3.1.- INTRODUCCIN.-
Adems de los disparadores 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

Prof: Juan Carlos Prez Jorge 39


I.E.S. TRASSIERRA - Crdoba PL/SQL

end [nombre_procedimiento] ;

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

2.- Compilar el fichero de texto ejecutndolo con el comando START <nombre_fichero>.


La ejecucin convierte el cdigo fuente en cdigo compilado y lo almacena en la base
de datos. La ejecucin se realiza desde SQL*Plus u otro interfaz que permita
sentencias LDD. El cdigo fuente se almacena siempre en la B.D. El cdigo
compilado solo se almacena si no se han producido errores. En este caso pueden verse
los errores de compilacin con el comando SHOW ERRORS.

3.- Invocar el procedimiento o funcin desde un entorno Oracle con el comando


EXECUTE. Por ejemplo:

EXECUTE altalum (1, 'JOS ANGEL FERNNDEZ') ;

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

Las siguientes son formas vlidas de invocacin:

EXECUTE altalum(:v_a, :v_b);


EXECUTE altalum(:v_a+1 , 'MARIA VALVERDE');
EXECUTE altalum(3, 'JOSE SANTAELLA');

Prof: Juan Carlos Prez Jorge 40


I.E.S. TRASSIERRA - Crdoba PL/SQL

3.2.- PROCEDIMIENTOS.-
Un procedimiento es un subprograma que realiza una accin especfica. Pueden recibir
parmetros pero que no devuelven ningn valor.

3.2.1.- Creacin y borrado.-

Se 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

donde:
nombre_proc Es el nombre del procedimiento.
argumento Es el nombre del argumento.
tipo_arg Indica el tipo de argumento: IN (por defecto), OUT o IN OUT.
tipo_dato El tipo de dato del argumento sin precisin.
bloque PL/SQL El cuerpo procedural que define la accin a realizar.

La opcin REPLACE se especifica cuando se desea reemplazar un procedimiento del mismo


nombre sin necesidad de borrarlo previamente. AS e IS son equivalentes.

El bloque PL/SQL debe comenzar con la palabra BEGIN o con una declaracin de variable
local. Nunca debe comenzar con DECLARE. Esta diferencia con los bloques PL/SQL
annimos ocurre porque AS (o IS) llevan implcito el DECLARE.

El procedimiento debe finalizar con la palabra END seguida opcionalmente por el nombre del
procedimiento y un punto y coma (;).

Para borrar un procedimiento usaremos la sentencia:

DROP PROCEDURE nombre_proc ;

3.2.2. Tipos de Argumentos.-

El 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.

Prof: Juan Carlos Prez Jorge 41


I.E.S. TRASSIERRA - Crdoba PL/SQL

Tipo Descripcin
IN 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 Permite devolver valores desde el procedimiento al entorno de


llamada. El argumento correspondiente acta como una variable no
inicializada, por lo que dentro del subprograma solo puede
asignrsele valores, no pudiendo aparecer en la parte derecha de
una expresin. En la invocacin del subprograma, este parmetro
solo puede sustituirse por una variable.

IN OUT Se usa para pasar parmetros por referencia y recogerlos del


procedimiento o funcin. El argumento correspondiente acta
como una variable inicializada, por lo que se le puede cambiar su
valor y usarse en la parte derecha de las expresiones. En la llamada,
este parmetro solo puede sustituirse por una variable.

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; /* equivalente a execute prueba('Sin Nombre', 5);*/


EXECUTE prueba ('Paco'); /* equivalente a execute prueba('Paco', 5); */
EXECUTE prueba ('Marta', 9);

Si quisiramos darle un valor a v2 y tomar el de v1 por defecto, deberamos usar la notacin


nominal:

EXECUTE prueba(v2=>8);

Es til y aconsejable declarar argumentos y variables utilizando los atributos % TYPE o


%ROWTYPE.

Veamos algunos ejemplos del uso de los tipos de argumentos:

Argumentos IN
Almacenar informacin acerca de un nuevo empleado:

CREATE OR REPLACE PROCEDURE alta_emp


(v_emp_numero IN temple.numem%TYPE ,
v_emp_departa IN temple.numde%TYPE ,
v_emp_telefono IN temple.extel%TYPE ,
v_emp_fechanac IN temple.fecna%TYPE ,
v_emp_fechaing IN temple.fecin%TYPE ,
v_emp_salario IN temple.salar%TYPE ,
v_emp_comision IN temple.comis%TYPE ,
v_emp_hijos IN temple.numhi%TYPE ,
v_emp_nombre IN temple.nomem%TYPE )

Prof: Juan Carlos Prez Jorge 42


I.E.S. TRASSIERRA - Crdoba PL/SQL

IS
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:

- Generar la clave primaria de una tabla utilizando un generador de se secuencia.


- Registrar el usuario partiendo de la variable USER.
- Registrar la fecha actual basndose en la variable SYSDATE.
- Almacenar valores por defecto, cuando sea apropiado.
- Utilizar reglas de negocio para calcular valores de entrada de forma automtica
utilizando una frmula.

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 IN temple.numem%TYPE ,


v_emp_departa IN temple.numde%TYPE ,
v_emp_telefono IN temple.extel%TYPE ,
v_emp_fechanac IN temple.fecna%TYPE ,
v_emp_hijos temple.numhi%TYPE ,
v_emp_nombre temple.nomem%TYPE ) IS
v_emp_fechaing temple.fecin%TYPE ;
v_emp_salario temple.salar%TYPE ;
v_emp_comision temple.comis%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;

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

Prof: Juan Carlos Prez Jorge 43


I.E.S. TRASSIERRA - Crdoba 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 temple.numem%TYPE ,
v_emp_nombre OUT temple.nomem%TYPE ,
v_emp_salario OUT temple.salar%TYPE ,
v_emp_comision OUT temple.comis%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.

3.2.3.- Polimorfismo.-

El 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.

Ejemplo:

Prof: Juan Carlos Prez Jorge 44


I.E.S. TRASSIERRA - Crdoba PL/SQL

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;

3.3.- FUNCIONES.-
Las 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.

3.3.1.- Creacin y borrado.-

La 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

Prof: Juan Carlos Prez Jorge 45


I.E.S. TRASSIERRA - Crdoba PL/SQL

(argumento [tipo] tipo_dato [,argumento [tipo] tipo_dato ] ..) RETURN tipo_dato


AS [IS] bloque PL/SQL

donde 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 temple.numem%TYPE) RETURN number

IS
v_emp_salario temple.salar%TYPE := 0;

BEGIN
SELECT salar INTO v_emp_salario
FROM temple
WHERE numem = v_emp_numero;

RETURN (v_emp_salario);
END tomar_salario;
/

Para usar la funcin podremos hacer:

SELECT nomem, tomar_salario(numem) FROM temple;

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 ;

3.3.2.- Recursividad.-

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

Prof: Juan Carlos Prez Jorge 46


I.E.S. TRASSIERRA - Crdoba PL/SQL

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;

La recursividad no es una herramienta considerada fundamental en la programacin PL/SQL.


Cualquier problema que requiera su utilizacin tambin puede ser resuelto utilizando
iteracin. Una versin iterativa de un programa es usualmente ms fcil de disear y de
entender. Sin embargo, la versin recursiva es ms simple, pequea y ms fcil de depurar. A
modo de ejemplo, observe las siguientes dos versiones de cmo calcular el nmero n-simo
de la serie de Fibonacci:

-- Versin recursiva
FUNCTION fib (n POSITIVE) RETURN INTEGER IS

BEGIN
IF (n = 1) OR (n = 2) THEN
RETURN 1;
ELSE
RETURN fib(n 1) + fib(n 2);
END IF;
END fib;

-- Versin iterativa
FUNCTION fib (n POSITIVE) RETURN INTEGER IS
pos1 INTEGER := 1;
pos2 INTEGER := 0;
cum INTEGER;
BEGIN
IF (n = 1) OR (n = 2) THEN
RETURN 1;
ELSE
cum := pos1 + pos2;
FOR i IN 3..n LOOP
pos2 := pos1;
pos1 := cum;
cum := pos1 + pos2;
END LOOP;
RETURN cum;
END IF;
END fib;

La versin recursiva es ms elegante que la iterativa, sin embargo esta ltima es ms eficiente,
corre ms rpido y utiliza menos memoria.

3.3.3.- Funciones PL/SQL en sentencias SQL.-

Dentro 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:

Prof: Juan Carlos Prez Jorge 47


I.E.S. TRASSIERRA - Crdoba PL/SQL

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.

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.
El valor resultante de la funcin tambin debe ser un tipo de dato Oracle.

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.
Slo las funciones locales que se referencian en la lista de la SELECT, en la clusula ,
VALUES de un INSERT o en la clusula SET de un UPDATE pueden actualizar una
variable definida en un paquete.
No pueden actualizar variables dentro de un paquete las funciones referenciadas en las
clusulas CONNECT BY, START WITH, ORDER BY o GROUP BY.
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.
Las funciones que leen o escriben en el estado de un paquete no pueden utilizar
paralelismo.

Prof: Juan Carlos Prez Jorge 48


I.E.S. TRASSIERRA - Crdoba PL/SQL

3.4.- PAQUETES.-
Los 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.

3.4.1.- Creacin y borrado.-

Los 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.

Prof: Juan Carlos Prez Jorge 49


I.E.S. TRASSIERRA - Crdoba PL/SQL

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

Cuando queramos borrar un paquete lo haremos con la orden

DROP PACKAGE nombre_paquete ;

A continuacin se expone un ejemplo de un paquete completo:

create or replace package acciones_empleados is


type registro_empleado is record (empleado number, salario number);
cursor salario_descendente (empleado number) return registro_empleado;
procedure alta_empleado (nombre varchar2 , trabajo varchar2 , salario number, dpto number) ;
procedure baja_empleado (id_empleado number);
end;
/

create or replace package body acciones_empleados is


cursor salario_descendente (empleado number) return registro_empleado is
select no_empleado, salario from empleados order by salario desc;

procedure alta_empleado ( nombre varchar2 , trabajo varchar2, salario number, dpto number) is
begin
insert into empleados values (sec_empleado.nextval, nombre, trabajo, salario, dpto);
end;

procedure baja_empleado (id_empleado number) is


begin
delete from empleados where empleado = id_empleado ;
end;
end;
/

3.4.2.- La depuracin en los paquetes.-

Al 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.

Prof: Juan Carlos Prez Jorge 50


I.E.S. TRASSIERRA - Crdoba PL/SQL

Sintaxis:
PRAGMA RESTRICT_REFERENCES ( nombre_func, WNDS
[,WNPS] [RNDS] [,RNPS] ) ;
Donde:

WNDS Indica que la funcin no puede modificar tablas de la base de datos. (Writes No
Database State). En este paquete es obligatoria.
WNPS Hace que la funcin no pueda cambiar los valores de variables de un paquete
pblico. (Writes No Package Status).
RNDS No permite que la funcin pueda consultar ninguna tabla de la base de datos.
(Reads No Database State).
RNPS Indica que la funcin no puede referenciar los valores de las variables de un
paquete pblico. (Reads No Database Status).

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

El nivel de depuracin de una funcin se debe especificar en la zona de especificacin del


paquete. Si el paquete contiene varias funciones con el mismo nombre, el nivel de depuracin
se aplica a la ltima.

Prof: Juan Carlos Prez Jorge 51


I.E.S. TRASSIERRA - Crdoba PL/SQL

La invocacin a una funcin empaquetada se hace de la misma forma que si fuera una
funcin SQL. Por ejemplo, para llamar a la funcin COMP (que se encuentra en el paquete
FINANZAS residente enm la BD de Barcelona) desde una sentencia SELECT, dentro de un
bloque PL/SQL, haramos:

DECLARE
interes NUMBER;
BEGIN
SELECT finanzas.comp@bcn(anos,cant,porc) INTO interes
FROM conta
WHERE no_cuenta = cuenta_id
END;

3.5.- VENTAJAS DE PROCEDIMIENTOS, FUNCIONES Y PAQUETES.-


El uso de procedimientos, funciones de usuario y paquetes presenta una serie de ventajas:

Modula el desarrollo de las aplicaciones.


Aumenta la seguridad y la integridad en la Base de Datos.
- Mayor independencia de los datos, al ser analizados dentro del servidor Oracle en vez
de desde dentro de una aplicacin.
- Control de acceso indirecto a objetos de la B.D. para usuarios no privilegiados.
Asegura que las acciones que estn relacionadas se ejecutan conjuntamente.
Aumenta del rendimiento
- Permite realizar clculos complejos, lentos o no disponibles en SQL
- Preanlisis de sentencias que ejecutan varios usuarios, utilizando el SQL compartido.
- Las sentencias PL/SQL se analizan en tiempo de compilacin y no en ejecucin.
- Reduccin del nmero de llamadas a la Base de Datos y el trfico por la red gracias
ala agrupacin de comandos.
- Posibilidad de manipular nuevos tipos de datos (por ejemplo latitud o longitud),
codificando cadenas de caracteres y utilizando funciones para operar con las cadenas.
Mejora en la utilizacin de la memoria
- Una nica copia del cdigo almacenado en la B.D. en lugar de mltiples copias del
mismo cdigo en aplicaciones diferentes.
- Utiliza SQL compartido para evitar el exceso de cursores.
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.

3.6.- MANEJO DE EXCEPCIONES.-


Los 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.

Prof: Juan Carlos Prez Jorge 52


I.E.S. TRASSIERRA - Crdoba PL/SQL

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


Comunicar el error interactivamente Omitir en el procedimiento el manejo de
errores
Oracle
Realizar una operacin en la base de datos Incluir el manejo de excepciones dentro
adaptando el mensaje de error. del procedimiento.
Comunicar el error interactivamente Llamar al procedimiento
RAISE APPLICA TION ERROR.
Definida por usuario
Realizar una operacin en la base de datos Incluir el manejo de excepciones dentro
adaptando el mensaje de error. del procedimiento

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

Mientras se est almacenando informacin para un empleado nuevo, comprobar que su


jefe existe como empleado:

CREATE OR REPLACE PROCEDURE alta_emp


(v_emp_no IN emp.empno%TYPE,
v_emp_name IN emp.ename%TYPE,
v_emp_job IN emp.job%TYPE,
v_mgr_no IN emp.mgr%TYPE,
v_emp_sal emp.sal%TYPE)
IS
v_emp_hiredate emp.hiredate%TYPE ;
v_emp_comm emp.comm%TYPE ;
v_emp_deptno emp.deptno%TYPE ;
BEGIN
v_emp_hiredate:=sysdate;
v_emp_comm:=0;
SELECT deptno INTO v_emp_deptno FROM emp WHERE empno = v_mgr_no;
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
VALUES (v_emp_no, v_emp_name, v_emp_job, v_mgr_no, v_emp_hiredate,
v_emp_sal, v_emp_comm, v_emp_deptno);
END alta_emp;
/

La siguiente sentencia provocara la respuesta:


SQL> EXECUTE alta_emp (1, 'PEPE', 'CLERK', 9999, 1000);
BEGIN alta_emp (1, 'PEPE', 'CLERK', 9999, 1000); END;

*
ERROR en lnea 1:
ORA-01403: no se han encontrado datos
ORA-06512: en "SCOTT.ALTA_EMP", lnea 14
ORA-06512: en lnea 1

Prof: Juan Carlos Prez Jorge 53


I.E.S. TRASSIERRA - Crdoba PL/SQL

Ejemplo: Propagar una excepcin definida por el usuario.

Recordemos que el procedimiento RAISE_APPLICATION_ERROR su usa para mostrar una


excepcin definida por el usuario de forma interactiva devolviendo un cdigo de error no
estndar y un mensaje.

Mientras se intenta borrar a un empleado, comprobar que el empleado especificado existe:

CREATE OR REPLACE PROCEDURE baja_emp (v_emp_numero IN temple.numem%TYPE) IS

BEGIN
DELETE FROM temple WHERE numem = v_emp_numero;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR (-20300, 'Empleado inexistente');
END IF;
END baja_emp;
/

La siguiente sentencia provocara la respuesta:


SQL> EXECUTE baja_emp(9999);
BEGIN baja_emp(9999); END;
*
ERROR en lnea 1:
ORA-20300: Empleado inexistente
ORA-06512: en "SCOTT.BAJA_EMP", lnea 6
ORA-06512: en lnea 1

Si se omite el manejo de excepciones RAISE_APPLICATION_ERROR para una excepcin


definida por el usuario y el procedimiento finaliza con un fallo, devolver un mensaje
indicando que la excepcin definida por el usuario ha fallado.

Si se incluye el manejo de excepciones, el proceso se direcciona a la zona de excepciones. El


desvo de excepciones definidas por el usuario acta de forma similar a las excepciones
Oracle, pero incluyendo su correspondiente manejador. Hay dos etapas adicionales: la
declaracin de la excepcin e invocarla de manera explcita con la sentencia RAISE.

Ejemplo: Desviar el flujo del programa a una excepcin Oracle predefinida.

Mientras se almacena informacin acerca de un nuevo empleado, comprobar que su jefe


existe como empleado.

CREATE OR REPLACE PROCEDURE alta_emp


(v_emp_no IN emp.empno%TYPE,
v_emp_name IN emp.ename%TYPE,
v_emp_job IN emp.job%TYPE,
v_mgr_no IN emp.mgr%TYPE,
v_emp_sal emp.sal%TYPE)
IS
v_emp_hiredate emp.hiredate%TYPE ;
v_emp_comm emp.comm%TYPE ;
v_emp_deptno emp.deptno%TYPE ;
BEGIN
v_emp_hiredate:=sysdate;
v_emp_comm:=0;

Prof: Juan Carlos Prez Jorge 54


I.E.S. TRASSIERRA - Crdoba PL/SQL

SELECT deptno INTO v_emp_deptno FROM emp WHERE empno = v_mgr_no;


INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
VALUES (v_emp_no, v_emp_name, v_emp_job, v_mgr_no, v_emp_hiredate,
v_emp_sal, v_emp_comm, v_emp_deptno);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR (-20201, 'El jefe indicado:'|| v_mgr_no||' no es empleado');
END alta_emp;
/

La siguiente sentencia provocara la respuesta:


SQL> EXECUTE alta_emp (1, 'PEPE', 'CLERK', 9999, 1000);
BEGIN alta_emp (1, 'PEPE', 'CLERK', 9999, 1000); END;
*
ERROR en lnea 1:
ORA-20201: El jefe indicado:9999 no es empleado
ORA-06512: en "SCOTT.ALTA_EMP", lnea 21
ORA-06512: en lnea 1

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.

Ejemplo: Desviar el flujo del programa a una excepcin Oracle NO-PREDEFINIDA.

Mientras se almacena informacin acerca de un nuevo empleado, comprobar que su jefe


existe como empleado.

CREATE OR REPLACE PROCEDURE alta_emp


(v_emp_no IN emp.empno%TYPE,
v_emp_name IN emp.ename%TYPE,
v_emp_job IN emp.job%TYPE,
v_mgr_no IN emp.mgr%TYPE,
v_emp_hiredate emp.hiredate%TYPE ,
v_emp_sal emp.sal%TYPE,
v_emp_comm emp.comm%TYPE )
IS
v_emp_deptno emp.deptno%TYPE ;
e_jefe_erroneo EXCEPTION;
PRAGMA EXCEPTION_INIT(e_jefe_erroneo, +100);
BEGIN
SELECT deptno INTO v_emp_deptno FROM emp WHERE empno = v_mgr_no;
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
VALUES (v_emp_no, v_emp_name, v_emp_job, v_mgr_no, v_emp_hiredate,
v_emp_sal, v_emp_comm, v_emp_deptno);
EXCEPTION
WHEN e_jefe_erroneo THEN
RAISE_APPLICATION_ERROR (-20291, 'Jefe '|| v_mgr_no||' no es empleado');
END alta_emp;
/

La siguiente sentencia provocara la respuesta:


SQL> EXECUTE alta_emp(1, PEPE', 'CLERK', 9999, '01-JUL-98', 1000, NULL);
BEGIN alta_emp(1, 'PEPE', 'CLERK', 9999, '01-JUL-98', 1000, NULL); END;

Prof: Juan Carlos Prez Jorge 55


I.E.S. TRASSIERRA - Crdoba PL/SQL

*
ERROR en lnea 1:
ORA-20291: Jefe 9999 no es empleado
ORA-06512: en "SCOTT.ALTA_EMP", lnea 20
ORA-06512: en lnea 1

3.7.- EJERCICIOS.-
3.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).

CREATE PROCEDURE aumento_salario (empleado integer, incremento real) IS


salario_actual real;
falta_salario exception;
BEGIN
SELECT salario INTO salario_actual FROM empleados WHERE no_empleado = empleado;
IF salario_actual IS NULL THEN
RAISE falta_salario;
ELSE
UPDATE empleados
SET salario = salario + incremento WHERE no_empleado = empleado;
END IF
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO mensajes VALUES (empleado, 'No existe el empleado'};
WHEN falta_salario THEN
INSERT INTO mensajes VALUES (empleado, 'No tiene salario');
END;
/

2.- Determinar si un nmero es par o impar. Recursividad por interinvocacin.

CREATE OR REPLACE package pq_par IS


FUNCTION par(n number) RETURN boolean;
FUNCTION impar(n number) RETURN boolean;
END pq_par;
/

CREATE OR REPLACE PACKAGE BODY pq_par IS


FUNCTION par (n number) RETURN boolean IS
BEGIN
IF n = 0 THEN RETURN TRUE;
ELSE RETURN impar(n-1);
END IF;
END;

FUNCTION impar (n number) RETURN boolean IS


BEGIN
IF n = 0 THEN RETURN FALSE;
ELSE RETURN par(n-1);
END IF;
END;
END pq_par;
/

Prof: Juan Carlos Prez Jorge 56


I.E.S. TRASSIERRA - Crdoba 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:

Tipos EmpRecTyp y DeptRecTyp


Cursor desc_salary
Excepcin invalid_salary
Funcionbes hire_employee and nth_highest_salary
Procedimientos fire_employee and raise_salary

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.
CREATE PACKAGE emp_actions AS

/* Declaracin pblica (visible desde fuera) de tipos, cursor y excepcin */


TYPE EmpRecTyp IS RECORD (emp_id INT, salary REAL);
TYPE DeptRecTyp IS RECORD (dept_id INT, location VARCHAR2);
CURSOR desc_salary RETURN EmpRecTyp;
invalid_salary EXCEPTION;

/* Declaracin de subprogramas. */
FUNCTION hire_employee ( ename VARCHAR2,
job VARCHAR2,
mgr REAL,
sal REAL,
comm REAL,
deptno REAL) RETURN INT;
PROCEDURE fire_employee (emp_id INT);
PROCEDURE raise_salary (emp_id INT, grade INT, amount REAL);
FUNCTION nth_highest_salary (n INT) RETURN EmpRecTyp;
END emp_actions;
/

CREATE PACKAGE BODY emp_actions AS


number_hired INT; -- visible solo desde este paquete

CURSOR desc_salary RETURN EmpRecTyp IS


SELECT empno, sal FROM emp ORDER BY sal DESC;

FUNCTION hire_employee ( 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;

Prof: Juan Carlos Prez Jorge 57


I.E.S. TRASSIERRA - Crdoba PL/SQL

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
UPDATE emp SET sal = sal + amount WHERE empno = emp_id;
ELSE
RAISE invalid_salary;
END IF;
END raise_salary;

FUNCTION nth_highest_salary (n INT) RETURN EmpRecTyp IS


emp_rec EmpRecTyp;
BEGIN
OPEN desc_salary;
FOR i IN 1..n LOOP
FETCH desc_salary INTO emp_rec;
END LOOP;
CLOSE desc_salary;
RETURN emp_rec;
END nth_highest_salary;
-- Esta es la parte opcional de inicializacin. Solo se ejecuta la primera vez
BEGIN -- que se hace referencia al paquete dentro de una misma sesin */
INSERT INTO emp_audit VALUES (SYSDATE, USER, EMP_ACTIONS);
number_hired := 0;
END emp_actions;
/

4.- Un ejemplo de paquete sin cuerpo:

CREATE PACKAGE trans_data AS


TYPE TimeRec IS RECORD ( 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.

Prof: Juan Carlos Prez Jorge 58


I.E.S. TRASSIERRA - Crdoba PL/SQL

3.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.

2.- Crear la funcin SUELDO_EMP, que recibir el nmero de un empleado y devolver su


sueldo total (salario+comisin). Si el empleado suministrado nbo existe, devolver el error
-20222 'Empleado inexistente'.

3.- Crear la funcin SUELDO_DEP, que haciendo uso de la funcin anterior, reciba un
nmero de departamento y devuelva su sueldo total.

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%.

5.- Crear el paquete PAQ_EMPLE que recoja todos los procedimientos y funciones
desarrollados:
alta_emp
baja_emp
consulta_emp
sueldo_emp
aumento_salario

Prof: Juan Carlos Prez Jorge 59

También podría gustarte