Vous êtes sur la page 1sur 33

PBD3301 PROGRAMACIN DE BASE DE DATOS

Usando Cursores Explcitos


Unidad de Aprendizaje N1
Construyendo Bloques PL/SQL

Aprendizaje Esperado :
Construye unidades de programacin, segn sintaxis, restricciones del lenguaje,
requisitos de la lgica de negocios y de informacin.
Utiliza recursos del lenguaje segn su sintaxis, restricciones, requisitos de la
lgica de negocios y de informacin.
DECLARE
CURSOR cur_emp IS
SELECT ..
;
BEGIN
FOR reg_emp IN cur_emp LOOP
.;
END LOOP;
END;
Objetivos de la Clase

Distinguir entre cursores implcitos y explcitos


Explicar cundo y por qu utilizar cursores explcitos
Declarar y controlar cursores explcitos
Usar Loop Simple y FOR Loop para obtener los datos del cursor explcito
Declarar y utilizar cursores con parmetros
Usar clusula FOR UPDATE para bloqueo de filas.
Usar clusula WHERE CURRENT OF para hacer referencia a la fila actual
del cursor explcito.
Trabajar con ms de un cursor explcito.
Cursores
Cada sentencia SQL ejecutada por el servidor de Oracle tiene un
cursor individual asociado:

Cursor Implcito Cursor Explcito


Cursores Explcitos

Filas Retornadas

100 King AD_PRES


101 Kochhar AD_VP
102 De Haan AD_VP
. . .
. . .
. . .
139 Seo ST_CLERK
140 Patel ST_CLERK
. . .

Set Activo
Control de Cursores Explcitos

SI

NO
Filas
DECLARE OPEN FETCH
a leer?

Crea un Identifica el Recupera la


rea de SQL fila actual en Verifica la
conjunto o
las variables existencia
con nombre set activo
de filas
Retorna a
FETCH si
existen filas

CLOSE

Libera el
set activo
Control de Cursores Explcitos

1 Abre el cursor. Puntero del Cursor

2 Lee una fila.

Puntero del cursor

Puntero del
cursor
3 Cierra el cursor.
Declarar el Cursor
Sintaxis:
CURSOR nombre_cursor IS
sentencia_select;

Ejemplos:

DECLARE DECLARE
CURSOR cur_emp IS v_locid NUMBER:= 1700;
SELECT employee_id, last_name CURSOR cur_dept IS
FROM employees SELECT *
WHERE department_id =30; FROM departments
WHERE location_id = v_locid;
Abrir el Cursor
Sintaxis:
OPEN nombre_cursor;

Ejemplo:

DECLARE
CURSOR cur_emp IS
SELECT employee_id, last_name
FROM employees
WHERE department_id =30;
...
BEGIN
OPEN emp_cursor;
Obtener Datos del Cursor
Sintaxis:
FETCH nombre_cursor INTO lista_de_variables;
FETCH nombre_cursor INTO registro_PL/SQL;

Ejemplo:
DECLARE
CURSOR cur_emp IS
SELECT employee_id, last_name
FROM employees
WHERE department_id =30;
v_lname employees.last_name%TYPE;
v_empno employees.employee_id%TYPE;
BEGIN
OPEN cur_emp;
FETCH cur_emp INTO v_empno, v_lname;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_lname);
END;
Obtener Datos del Cursor
Ejemplo:
DECLARE
CURSOR c_emp_cursor IS
SELECT employee_id, last_name FROM employees
WHERE department_id =30;
v_empno employees.employee_id%TYPE;
v_lname employees.last_name%TYPE;
BEGIN
OPEN c_emp_cursor;
LOOP
FETCH c_emp_cursor INTO v_empno, v_lname;
EXIT WHEN c_emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( v_empno ||' '||v_lname);
END LOOP;
END;
Cerrar el Cursor
Sintaxis:
CLOSE nombre_cursor;

Ejemplo:
DECLARE
CURSOR cur_emp IS
SELECT employee_id, last_name
FROM employees
WHERE department_id =30;
lname employees.last_name%TYPE;
empno employees.employee_id%TYPE;
BEGIN
OPEN cur_emp;
FETCH emp_cursor INTO empno, lname;
DBMS_OUTPUT.PUT_LINE(empno || ' ' || lname);
CLOSE cur_emp;
END;
Atributos para Cursores Implcitos
Hay cuatro atributos para obtener informacin del estado de un cursor
explcito.

%ISOPEN: Atributo de tipo Booleano que retorna TRUE si el


cursor se encuentra abierto.

%NOTFOUND: Atributo de tipo Booleano que retorna TRUE si el


FECTH ms reciente no retorna filas.

%FOUND: Atributo de tipo Booleano que Retorna TRUE si el


FETCH ms reciente retorna una fila.

%ROWCOUNT: Atributo de tipo numrico que retorna el nmero


total de filas procesadas.
Atributo %ISOPEN
Se pueden leer filas slo cuando el cursor se encuentra abierto. El
atributo de cursor %ISOPEN permite validar si el cursos est abierto
antes de realizar una lectura.

Ejemplo:
IF NOT cur_emp%ISOPEN THEN
OPEN cur_emp;
END IF;
LOOP
FETCH cur_emp ...
Atributos %ROWCOUNT y %NOTFOUND
El atributo de cursor %ROWCOUNT permite procesar un nmero
exacto de las filas. %ROWCOUNT y %NOTFOUND pueden ser
usados para condiciones de salida en un loop.

Ejemplo:
DECLARE
v_empleado VARCHAR2(60);
CURSOR cur_emp IS
SELECT first_name || ' ' || last_name
FROM employees;
BEGIN
OPEN cur_emp;
LOOP
FETCH cur_emp INTO v_empleado;
EXIT WHEN cur_emp%ROWCOUNT > 10 OR
cur_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empleado);
END LOOP;
CLOSE cur_emp;
END;
Cursores y Registros
El atributo %ROWTYPE permite definir un registro basado en las
columnas seleccionadas en un cursor explcito.
Los valores de la fila leda desde el cursor se almacenan directamente
en los campos correspondientes del registro.

Ejemplo:
DECLARE
CURSOR cur_emp IS
SELECT employee_id, last_name
FROM employees
WHERE department_id = 30;
reg_emp cur_emp%ROWTYPE;
BEGIN
OPEN cur_emp;
LOOP
FETCH cur_emp INTO reg_emp;
EXIT WHEN cur_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(reg_emp.employee_id || ' ' || reg_emp.last_name);
END LOOP;
CLOSE cur_emp;
END;
Manejo del Cursor: Loop Simple
Para poder iterar a travs del cursor se puede usar LOOP Simple.
Esto permite leer todas las filas (o una cantidad de filas determinadas)
del cursor de acuerdo a la condicin de salida del loop.

Sintaxis:
OPEN nombre_cursor;
LOOP
FETCH nombre_cursor INTO lista_variables | registro_PL/SQL;
EXIT WHEN nombre_cursor%NOTFOUND | EXIT WHEN nombre_cursor%ROWCOUNT;
/* Procesamiento de los registros recuperados y ejecucin de sentencias */
END LOOP;
CLOSE nombre_cursor;
Manejo del Cursor: Loop Simple
Ejemplo:
DECLARE
CURSOR cur_emp IS
SELECT employee_id, last_name
FROM employees
WHERE department_id =30;
lname employees.last_name%TYPE;
empno employees.employee_id%TYPE;
BEGIN
OPEN cur_emp;
LOOP
FETCH emp_cursor INTO empno, lname;
EXIT WHEN cur_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(empno || ' ' || lname);
END LOOP;
CLOSE cur_emp;
END;
Manejo del Cursor: WHILE LOOP
La instruccin FETCH aparece dos veces.
Para leer todas filas se utiliza WHILE LOOP.
Para validar que existan filas en el cursor se utiliza el atributo
%FOUND.

Sintaxis:
OPEN nombre_cursor;
FETCH nombre_cursor INTO lista_variables;
WHILE nombre_cursor%FOUND
LOOP
/* Procesamiento de los registros recuperados y ejecucin de sentencias*/
FETCH nombre_cursor INTO lista_variables;
END LOOP;
CLOSE nombre_cursor;
Manejo del Cursor: WHILE LOOP
Ejemplo:
DECLARE
CURSOR cur_emp IS
SELECT employee_id, last_name FROM employees
WHERE department_id =30;
empno employees.employee_id%TYPE;
lname employees.last_name%TYPE;
BEGIN
OPEN cur_emp;
FETCH cur_emp INTO empno, lname;
WHILE cur_emp%FOUND LOOP
DBMS_OUTPUT.PUT_LINE( empno ||' '||lname);
FETCH emp_cursor INTO empno, lname;
END LOOP;
CLOSE cur_emp;
END;
Manejo del Cursor: FOR LOOP
Es el mtodo ms fcil para procesar cursores explcitos ya que se
ejecutan implcitamente las instrucciones OPEN, FETCH, EXIT y
CLOSE

Sintaxis:
FOR nombre_registro IN nombre_cursor LOOP
/* Procesamiento de los registros recuperados y ejecucin de sentencias*/
END LOOP;
Manejo del Cursor: FOR LOOP
Ejemplo:
DECLARE
CURSOR cur_emp IS
SELECT employee_id, last_name
FROM employees
WHERE department_id =30;
BEGIN
FOR reg_emp IN cur_emp LOOP
DBMS_OUTPUT.PUT_LINE( reg_emp.employee_id || ' ' || reg_emp.last_name);
END LOOP;
END;
Cursor FOR LOOP usando Subconsultas
No hay necesidad de declarar el cursor.

Ejemplo:
BEGIN
FOR emp_record IN (SELECT employee_id, last_name
FROM employees
WHERE department_id =30)
LOOP
DBMS_OUTPUT.PUT_LINE( emp_record.employee_id ||' '||emp_record.last_name);
END LOOP;
END;
Cursores con Parmetros
Permite abrir y cerrar un cursor explcito muchas veces en un bloque
retornando un set activo diferente en cada ocasin.

Sintaxis:

CURSOR nombre_cursor[(nombre_parmetro tipo_dato, ...)] IS


sentencia_select;

OPEN nombre_cursor(valor_parmetro,.....) ;
Cursores con Parmetros
Ejemplo:
DECLARE
CURSOR emp_cursor (p_deptno NUMBER) IS
SELECT employee_id, last_name
FROM employees
WHERE department_id = p_deptno;
v_empno employees.employee_id%TYPE;
v_lname employees.last_name%TYPE;
BEGIN
OPEN emp_cursor (30);
DBMS_OUTPUT.PUT_LINE('Empleados Depto 30');
LOOP
FETCH emp_cursor INTO v_empno, v_lname;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(' ' || rpad(v_empno, 19, ' ') ||' '||v_lname);
END LOOP;
CLOSE emp_cursor;
OPEN emp_cursor (20);
DBMS_OUTPUT.NEW_LINE();
DBMS_OUTPUT.PUT_LINE('Empleados Depto 20');
LOOP
FETCH emp_cursor INTO v_empno, v_lname;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(' ' || rpad(v_empno, 19, ' ') ||' '|| v_lname);
END LOOP;
CLOSE emp_cursor;
END;
Clusula FOR UPDATE
Bloquea en forma explcita las filas, antes de su actualizacin o
eliminacin, para no permitir el acceso a otras sesiones mientras se
realiza la transaccin.

Sintaxis:
CURSOR nombre_cursor
SELECT ...
FROM ...
FOR UPDATE [OF column_referenciada][NOWAIT | WAIT n];

Ejemplo:
DECLARE
CURSOR c_emp_cursor IS
SELECT employee_id, last_name
FROM employees
WHERE department_id = 80 FOR UPDATE OF salary NOWAIT;
..
Clusula WHERE CURRENT
Se utiliza junto con la clusula FOR UPDATE para hacer referencia a
la fila actual de un cursor explcito.

Sintaxis:
BEGIN
{UPDATE|DELETE}... WHERE CURRENT OF nombre_cursor ;
Clusula WHERE CURRENT
Ejemplo:
DECLARE
empleado employees%ROWTYPE;
CURSOR emp_cursor IS
SELECT *
FROM employees
WHERE department_id = 100
FOR UPDATE;
BEGIN
OPEN emp_cursor; -- Se produce el bloqueo
LOOP
FETCH emp_cursor INTO empleado;
EXIT WHEN emp_cursor%NOTFOUND;
IF empleado.salary < 7000 THEN
UPDATE employees
SET salary=salary + salary *.10
WHERE CURRENT OF emp_cursor;
END IF;
END LOOP;
CLOSE emp_cursor; -- No libera bloqueos
COMMIT; /*Libera el bloqueo de las filas del cursor FOR UPDATE*/
END ;
Cursores con Subconsultas
Una subconsulta es una consulta SQL que proporciona una valor o set
de valores para la consulta externa.
Ejemplo:
DECLARE
CURSOR mi_cursor IS
SELECT first_name || ' ' || last_name, salary
FROM employees
WHERE salary < (SELECT ROUND(AVG(salary))
FROM employees)
ORDER BY salary, last_name;
nombre VARCHAR2(50);
salario employees.salary%TYPE;
BEGIN
OPEN mi_cursor;
DBMS_OUTPUT.PUT_LINE(' FUNCIONARIOS CON SALARIO MENOR AL PROMEDIO ');
DBMS_OUTPUT.PUT_LINE(' ---------------------------------------- ');
LOOP
FETCH mi_cursor INTO nombre, salario;
EXIT WHEN mi_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(rpad(nombre, 25, ' ' ) || ' : ' || TO_CHAR(salario, '$999,999'));
END LOOP;
CLOSE mi_cursor;
END;
Cursores con Subconsultas

SALARIO PROMEDIO

SALIDA DEL BLOQUE PL/SQL

...................
...................
Trabajando con ms de un Cursor
Ejemplo:
DECLARE
CURSOR cur_deptos IS
SELECT department_id, department_name
FROM departments;
CURSOR cur_emp_depto(deptno NUMBER) IS
SELECT first_name || ' ' || last_name nombre_emp
FROM employees
WHERE department_id = deptno;
v_total_emp NUMBER(2);
BEGIN
DBMS_OUTPUT.PUT_LINE(' Empleados por Departamento');
DBMS_OUTPUT.PUT_LINE('===================================');
DBMS_OUTPUT.NEW_LINE();
FOR reg_deptos IN cur_deptos LOOP
DBMS_OUTPUT.PUT_LINE('Departamento: '|| reg_deptos.department_name);
DBMS_OUTPUT.PUT_LINE('=====================================');
v_total_emp := 0;
FOR reg_emp_depto IN cur_emp_depto(reg_deptos.department_id) LOOP
DBMS_OUTPUT.PUT_LINE(reg_emp_depto.nombre_emp);
v_total_emp := v_total_emp + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('=====================================');
DBMS_OUTPUT.PUT_LINE('Total de Empleados: ' || v_total_emp);
DBMS_OUTPUT.NEW_LINE();
END LOOP;
END;
Trabajando con ms de un Cursor

...................
...................

SALIDA DEL BLOQUE PL/SQL


...................
...................

...................
...................
Resumen de la Clase
Se explicaron las diferencias entre cursores implcitos y explcitos.
Se explic cundo y por qu utilizar cursores explcitos
Se explic cmo declarar y controlar cursores explcitos
Se explic cmo Usar Loop Simple y FOR Loop para obtener los datos del
cursor explcito
Se explic cmo declarar y utilizar cursores con parmetros
Se explic el uso de la clusula FOR UPDATE para bloqueo de filas.
Se explic el uso de la clusula WHERE CURRENT OF para hacer
referencia a la fila actual del cursor explcito.
Se explic cmo trabajar con ms de un cursor explcito.