Está en la página 1de 39

PL/SQL

Cursores
Cursores

Tipos de cursores
mplicitos: declarados automticamente para todas
las sentencias DML y SELECT PL/SQL.
Explcitos: Declarados y nombrados por el
programador.
Control de cursores explcitos
Puntero
Recupere una fila del cursor.
Continue hasta que quede vaco.
Puntero
Puntero





















Cursor
Cursor
Cursor
Abra el cursor.
Declaracin del cursor
No se debe incluir la clusula INTO en la declaracin del cursor.
Se puede usar ORDER BY
CURSOR nombre_cursor IS
sentencia_select;
CURSOR c1 IS
SELECT *
FROM emp
WHERE deptno=10;
Apertura del cursor
Se tiene que abrir el cursor para ejecutar la consulta e
identificar el juego activo.
Si la consulta no devuelve ninguna fila, no se producir
ninguna excepcin.
Utilice los atributos del cursor para comprobar los
resultados producidos tras una recuperacin.
OPEN nombre_cursor;
OPEN c1;
Recuperacin de datos del cursor

Recupera los valores de la fila actual y los introduce en variables de salida.
Debe incluir el mismo nmero de variables que columnas devuelve el
cursor.
Las variables y las columnas estn relacionadas posicionalmente.
Se debe comprobar si el cursor tiene filas.
FETCH nombre_cursor INTO [variable1, variable2, ...]
| nombre_registro];
Recuperacin de datos del cursor (II)
Ejemplo
FETCH c1 INTO v_emp;
...
OPEN c1;
LOOP
FETCH c1 INTO v_emp
EXIT WHEN ...;
...
-- Proceso de recuperar los datos
...
END;
Cierre del cursor
Cierre el cursor una vez completado el procesamiento
de las filas.
Vuelva a abrir el cursor si es necesario
No intente recuperar los datos de un cursor una vez ha
sido cerrado
CLOSE nombre_cursor;
CLOSE c1;
%NOTFOUND Y %ROWCOUNT
Usa %ROWCOUNT para recuperar un nmero exacto de filas

Usa %NOTFOUND para determinar cundo salir del bucle
LOOP
FETCH ename_cursor INTO v_ename,
v_deptno;
IF ename_cursor%ROWCOUNT > 20 THEN
...
EXIT WHEN ename_cursor%NOTFOUND;
...
END LOOP;
Ejercicios
Utiliza un cursor explcito para mostrar los nombres de
los empleados de un departamento (p.ej. El 10) dentro
de un bloque PL/SQL.

Muestra los nombres y el salario de (los 5) empleados
con mayor salario.

DECLARE
CURSOR mi_emp_cursor IS
SELECT ename
FROM emp
WHERE deptno=10;
v_nombre emp.ename%TYPE;
BEGIN
OPEN mi_emp_cursor;
LOOP
FETCH mi_emp_cursor INTO v_nombre;
EXIT WHEN mi_emp_cursor%NOTFOUND;
dbms_output.put_line(v_nombre);
END LOOP;
CLOSE mi_emp_cursor;
END;
/
DECLARE
CURSOR mi_emp_cursor IS
SELECT ename,sal
FROM emp WHERE deptno=10;
v_empleado mi_emp_cursor%ROWTYPE;
BEGIN
OPEN mi_emp_cursor;
LOOP
FETCH mi_emp_cursor INTO v_empleado;
EXIT WHEN mi_emp_cursor%NOTFOUND;
dbms_output.put_line(v_empleado.ename);
END LOOP;
CLOSE mi_emp_cursor;
END;
/
/* Bsqueda de los empleados mejor pagados pej. top 5 */

SQL> CREATE TABLE top_emps
2> (name VARCHAR2(25),
3> salary NUMBER(11,2);
/* creara una nueva tabla en la que almacenarlos */

SET VERIFY OFF
ACCEPT p_num PROMPT Por favor, teclee el nmero de top empleados que
desee listar: ;
DECLARE
v_num NUMBER(3) := &p_num;
v_ename emp.ename%TYPE ;
v_sal emp.sal%TYPE ;
CURSOR emp_cursor IS
SELECT ename, sal
FROM emp
WHERE sal IS NOT NULL
ORDER BY sal DESC;
..
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO v_ename, v_sal;
WHILE emp_cursor%ROWCOUNT <= v_num AND
emp_cursor%FOUND LOOP
INSERT INTO top_emps (name, salary)
VALUES (v_name, v_sal);
FETCH emp_cursor INTO v_ename, v_sal;
END LOOP;
CLOSE emp_cursor;
COMMIT;
END;
/
Cursores y registros
Procesa las filas del juego activo de forma conveniente recuperando
valores e introducindolos en una variable de tipo registro.

Ejemplo:

DECLARE
...
CURSOR emp_cursor IS
SELECT empno, sal, hiredate, rowid
FROM emp
WHERE deptno = 20;
emp_record emp_cursor%ROWTYPE;

BEGIN
OPEN emp_cursor;
. . .
FETCH emp_cursor INTO emp_record;

Bucles FOR de cursor
Facilita el procesamiento de cursores explcitos
Apertura, recuperacin y cierre implcitos.
No declarar la variable registro, se declara implcitamente.
FOR nombre_registro IN nombre_cursor LOOP
sentecia1;
sentencia2;
. . .
END LOOP;
Ejercicios
Repite los ejercicios anteriores utilizando un
bucle FOR de cursor.

Introduce los nombres de todos los empleados
en una tabla PL/SQL. Recorre despus la tabla
y muestra los nombres por pantalla.


/* Ejemplo con doble cursor para recuperar todos los
empleados de todos los departamentos */
DECLARE
v_current_deptno dept.deptno%TYPE;
v_emp VARCHAR2(50);
CURSOR dept_cursor IS
SELECT deptno
FROM dept
ORDER BY deptno;
CURSOR emp_cursor (v_deptno NUMBER) IS
SELECT ename || Departamento ||TO_CHAR(deptno)
FROM emp
WHERE deptno = v_deptno;
..

..
BEGIN
OPEN dept_cursor;
LOOP
FETCH dept_cursor INTO v_current_deptno;
EXIT WHEN dept_cursor%NOTFOUND;
IF emp_cursor%ISOPEN THEN
CLOSE emp_cursor;
END IF;
OPEN emp_cursor (v_current_deptno);
LOOP
FETCH emp_cursor INTO v_emp;
EXIT WHEN emp_cursor%NOTFOUND;
dbms_output.put_line (Recuperado empleado || v_emp.ename);
END LOOP;
CLOSE emp_cursor;
END LOOP;
CLOSE dept_cursor;
COMMIT;
END;
/

PL/SQL
Excepciones
Gestin de excepciones
Interrumpir la Excepcin Propagar la Excepcin
Surge la excepcin
Se interrumpe la
excepcin
Surge la excepcin
La excepcin se propaga
al entorno de llamadas
DECLARE
BEGIN
EXCEPTION
END;
DECLARE
BEGIN
EXCEPTION
END;
No se interrumpe
la excepcin
Tipos de excepciones
Predefinidas por el Servidor
Oracle

No predefinida por el
Servidor


Definida por el usuario
Provocada
implcitamente
Provocada
explcitamente
Interrupcin de excepciones
EXCEPTION
WHEN excepcin1 [OR excepcin2 . . .] THEN
sentencia1;
sentencia2;
. . .
[WHEN excepcin3 [OR excepcin4 . . .] THEN
sentencia1;
sentencia2;
. . .]
[WHEN OTHERS THEN
sentencia1;
sentencia2;
. . .]
Interrupcin de Errores
Predefinidos por el Servidor Oracle
Haga referencia al nombre estndar en la rutina
de gestin de excepciones
Ejemplos de excepciones predefinidas
NO_DATA_FOUND
TOO_MANY_ROWS
INVALID_CURSOR
ZERO_DIVIDE
DUP_VAL_ON_INDEX
LOGIN_DENIED
Ejercicio
Del nombre de un empleado introducido durante
ACCEPT crea un bloque PL/SQL que devuelva
su nmero y su salario.

Trata los siguientes casos mostrando el
mensaje correspondiente:
No existe ningn empleado con ese nombre
Existen varios empleados con ese nombre
Se produce otro error distinto
/* Ejemplo - Bsqueda de empleados a partir de sueldo con excepciones */

SET VERIFY OFF

ACCEPT p_sal PROMPT Por favor, especifique el salario por considerar: ;

DECLARE
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE := &p_sal;

BEGIN
SELECT ename
INTO v_ename
FROM emp
WHERE sal = v_sal;
dbms_output.put_line(v_empleado.ename|| gana ||v_sal||Euros anuales);
..





..
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line(No existe ningn empleado que
gane||v_sal||Euros anuales);
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line(Existe ms de un empleado que
gane||v_sal||Euros anuales);
WHEN OTHERS THEN
WHEN no_data_found THEN
dbms_output.put_line(Error inesperado Avise al Servicio de
Informtica);
END;
/

Interrupcin de Excepciones
definidas por el usuario
Declare Reference
Seccin
declarativa
Seccin de gestin
De excepciones
Especifique la
excepcin
Gestione la
excepcin
Raise
Provoque
explcitamente la
excepcin utilizando la
sentencia RAISE
Seccin
Ejecutable
/* Ejemplo ahora con manejador que comunique mensaje a usuario si el
departamento no existe */

SET VERIFY OFF

ACCEPT p_deptno PROMPT Por favor, especifique el departamento: ;
ACCEPT p_loc PROMPT Especifique la localizacion del departamento: ;

DECLARE
e_dept_no_valido EXCEPTION;
v_deptno dept.deptno%TYPE := &p_deptno;

BEGIN
UPDATE dept
SET loc = &&p_loc
WHERE deptno = v_deptno;
..






..
IF SQL%NOTFOUND THEN
RAISE e_dept_no_valido
END IF;
COMMIT;

EXCEPTION
WHEN e_dept_no_valido THEN
dbms_output.put_line(El departamento
||TO_CHAR(v_deptno) ||introducido no es un departamento
vlido);
END;
/

PL/SQL
Disparadores
Creacin de disparadores
Momento:
BEFORE
AFTER

Evento
INSERT
UPDATE
DELETE
Nombre de tabla:
ON table

Tipo de trigger
Fila
Sentencia

WHEN condicin

Cuerpo del trigger
Momento de un disparador
BEFORE
No queremos permitir que se complete la sentencia del
disparador en caso de una excepcin o de no cumplir una
comprobacin realizada en el disparador.
Derivar valores de columna antes de completar una sentencia
INSERT o UPDATE
AFTER
Cuando queremos que la sentencia se complete antes de
ejecutar la accin del disparador.
Para completar acciones del disparador BEFORE.
Para realizar auditoras
Tipos de disparador
Cuntas veces se ejecuta un disparador?

Sentencia
Una nica vez cuando se produce el eventos (incluso si no
afecta a ningn registro)

Fila
Una vez por cada registro de la tabla afectada por el evento.
Cuerpo del disparador
Accin a realizar por el disparador

Se especifica mediante un bloque PL/SQL

Los disparadores tiene acceso a los valores de
columna nuevos y viejos del registro que se est
procesando.
Sintaxis
CREATE [OR REPLACE] TRIGGER
nombre_disparador
Tiempo evento1 [OR evento2 OR evento3]
ON nombre_tabla
BLOQUE PL/SQL;
Ejercicios
Crea un disparador que antes de insertar en la
tabla empleados compruebe que sea una hora
laborable (entre las 8:00 am y las 20:00 pm) y si
no es as que provoque un error.

CREATE OR REPLACE PROCEDURE operacin_segura
IS
BEGIN
IF TO_CHAR(SYSDATE, HH24:MI NOT BETWEEN 08:00 AND
20:00
OR TO_CHAR(SYSDATE, DY) IN (SAT, SUN) THEN
RAISE _APPLICATION_ERROR (-20205, Usted no est
autorizado a acceder fuera de horas normales de trabajo);
END IF;
END operacin_segura;
/

/* creacin de un disparador que llame al procedimiento de arriba */
/* en caso necesario */

CREATE OR REPLACE TRIGGER modo_seguro
BEFORE INSERT OR UPDATE OR DELETE on emp;
BEGIN
modo_seguro;
END modo_seguro;
/