Está en la página 1de 23

CONCEPTO Y USO DE

CURSORES

Facultad Politécnica Base de Datos II 1


Cursor SQL
 Un CURSOR es un área de trabajo privada para acceder a
las filas recuperadas por una sentencia SELECT de SQL
 Hay dos tipos de cursores:
 Implícitos: se declaran automáticamente para las
sentencias DML y SELECT.
ORACLE utiliza cursores implícitos para efectuar el parse
(análisis) y ejecutar los comandos SQL.

 Explícitos: Declarados y nombrados explícitamente


por el programador. Se puede declarar un cursor de
este tipo para manejar individualmente las filas
devueltas por consultas que devuelven más de una fila.

Facultad Politécnica Base de Datos II 2


Cursores explícitos
 Un cursor explícito requiere una
declaración que define la sentencia
SELECT en cualquier parte de la sección
declarativa de un bloque PL/SQL. Se
define con un nombre (los cursores
implícitos no se declaran y la manera de
referenciarse a ellos es con el prefijo
'SQL')
 Permite un control más preciso en el
procesamiento de las filas recuperadas
con la sentencia SQL

Facultad Politécnica Base de Datos II 3


Control de cursores explícitos

Yes
NOTFOUND?
DECLARE OPEN FETCH (vacío)
CLOSE

Crea un área Permite la Recupera la • Verifica si Libera el


de cursor apertura del fila actual y la existen filas conjunto
(se define cursor con el descarga en • Si encuentra activo
con un nombre variables filas, retorna
nombre) declarado al FETCH

Facultad Politécnica Base de Datos II 4


Controlando Cursores Explícitos

Abre el cursor
Pointer
(Puntero
o Indicador)
Fetch (recuperación) Cursor
de una fila por el
cursor

Puntero

Cursor
Continúa hasta que el
archivo esté vacío
Puntero

Cursor

Facultad Politécnica Base de Datos II 5


SINTAXIS DE LA DECLARACIÓN

• Declarar el cursor, es darle un nombre y asociarlo a


una consulta específica

DECLARE
DECLARE
CURSOR nombre_cursor IS
CURSOR nombre_cursor IS
Sentencia_select;
Sentencia_select;

• Se puede incluir variables en las sentencias SELECT


que serán sustituidas por valores que permitirán variar
el cursor
• No debe incluir la cláusula INTO dentro de la
declaración del cursor

Facultad Politécnica Base de Datos II 6


Declarando un Cursor: Ejemplo
Declarando un cursor para obtener la identificación del
artículo, nombre del artículo y cantidad a partir del
detalle de ventas de un ID de venta dado.

DECLARE
V_ID_VENTA B_DETALLE_vENTAS.Id_Venta%TYPE := 1;
V_ID B_ARTICULOS.ID%TYPE;
V_NOMBRE B_ARTICULOS.NOMBRE%TYPE;
V_CANTIDAD B_DETALLE_VENTAS.CANTIDAD%TYPE;
CURSOR C_VENTAS IS
SELECT v.id_articulo, a.nombre, v.cantidad
FROM b_Detalle_ventas v, b_articulos a
WHERE a.id = v.id_articulo AND
v. id_venta = v_id_venta;
…….

Facultad Politécnica Base de Datos II 7


Apertura del Cursor: Sintaxis

Al abrir el cursor, se ejecuta la consulta y se identifica el


"result set", que consiste en cada fila que cumple con la
condición where de la consulta:

OPEN
OPEN nombre_cursor;
nombre_cursor;

Si el Query no devuelve ninguna fila, no se levanta una


excepción.
Las filas del cursor no son devueltas al ejecutar el OPEN, sino
mediante la sentencia FETCH.

OPEN C_VENTAS;

Facultad Politécnica Base de Datos II 8


Recorrido del Cursor:
Sintaxis

• FETCH recupera una por una las filas devueltas


por la consulta: toma la fila actual y avanza el
cursor a la siguiente fila del result set.
• Se puede guardar el valor de cada columna por
separado, en variables distintas, o almacenar la
fila completa en un registro declarado utilizando
%ROWTYPE.
• Normalmente se utiliza FETCH dentro de un ciclo
LOOP-EXIT WHEN.

Facultad Politécnica Base de Datos II 9


Leyendo Datos del Cursor:
Fetch - Ejemplo

Recupere los datos del cursor definido anteriormente


sobre el detalle de ventas:

FETCH
FETCH C_VENTAS
C_VENTAS INTO
INTO V_ID,
V_ID, V_NOMBRE,
V_NOMBRE, V_CANTIDAD;
V_CANTIDAD;

Facultad Politécnica Base de Datos II 10


Cerrando el Cursor: Sintaxis

 Cierre el cursor después de completar el


procesamiento de las filas
 Si lo requiere, vuelva a abrir el cursor: esto
ejecutará nuevamente el query
 No intente realizar operaciones una vez que el
cursor ha sido cerrado. Esto levantará la excepción
INVALID_CURSOR

CLOSE
CLOSE nombre_cursor;
nombre_cursor;

Facultad Politécnica Base de Datos II 11


Atributos de Cursores Explícitos

Los atributos retornan información sobre la ejecución de un query.


Para utilizarlos, se preceden con el nombre del cursor como prefijo:

Atributo Tipo Descripción


%ISOPEN Boolean VERDADERO cuando el cursor
está abierto
%NOTFOUND Boolean VERDADERO cuando el FETCH
no retorna fila alguna
%FOUND Boolean VERDADERO cuando el FETCH
retorna alguna fila
%ROWCOUNT Number Devuelve el número total de filas
retornadas hasta el momento

Facultad Politécnica Base de Datos II 12


Controlando Múltiples Fetch

• Para procesar varias filas del cursor utilice un LOOP


• Lea (Con FETCH) una fila con cada iteración
• Escriba una prueba para determinar si existen más
filas que procesar con el atributo %NOTFOUND de la
siguiente forma:

IF nombre_cursor%NOTFOUND

• Si no se tienen filas que procesar debe forzar la


salida del LOOP

Facultad Politécnica Base de Datos II 13


El Atributo % ISOPEN : Ejemplo

 Recupere filas cuando el cursor está abierto.


 Pruebe si el cursor está abierto mediante el atributo
%ISOPEN antes de realizar un Fetch:

IF
IF C_VENTAS%ISOPEN
C_VENTAS%ISOPEN THEN
THEN
FETCH
FETCH C_VENTAS
C_VENTAS INTO
INTO V_ID,
V_ID, V_NOMBRE,
V_NOMBRE, V_CANTIDAD;
V_CANTIDAD;
ELSE
ELSE
OPEN
OPEN C_VENTAS;
C_VENTAS;
END
END IF;
IF;

Facultad Politécnica Base de Datos II 14


Los Atributos % NOTFOUND y
% ROWCOUNT: Ejemplo

• Recupere un número exacto de filas utilizando el atributo


%ROWCOUNT
• Determine cuándo terminar el Loop utilizando el atributo
%NOTFOUND

LOOP
LOOP
FETCH
FETCH C_VENTAS
C_VENTAS INTO
INTO V_ID,
V_ID, V_NOMBRE,
V_NOMBRE, V_CANTIDAD;
V_CANTIDAD;
EXIT
EXIT WHEN
WHEN C_VENTAS%ROWCOUNT
C_VENTAS%ROWCOUNT >> 55
OR
OR C_VENTAS%NOTFOUND;
C_VENTAS%NOTFOUND;
END
END LOOP;
LOOP;

Facultad Politécnica Base de Datos II 15


Cursores y Registros: Ejemplo
Procese las filas del conjunto activo convenientemente leyendo
valores en un REGISTRO PL/SQL
DECLARE
DECLARE
CURSOR
CURSOR C_VENTAS
C_VENTAS IS
IS
SELECT
SELECT v.id_articulo,
v.id_articulo, a.nombre,
a.nombre, v.cantidad
v.cantidad
FROM
FROM b_Detalle_ventas
b_Detalle_ventas v, b_articulos aa
v, b_articulos
WHERE
WHERE a.id
a.id == v.id_articulo
v.id_articulo AND
AND
v.
v. id_venta
id_venta == 1;
1;
R_VENTAS
R_VENTAS C_VENTAS%ROWTYPE;
C_VENTAS%ROWTYPE;

BEGIN
BEGIN
OPEN
OPEN C_VENTAS;
C_VENTAS;
LOOP
LOOP
FETCH
FETCH C_VENTAS
C_VENTAS INTO
INTO R_VENTAS;
R_VENTAS;
EXIT
EXIT WHEN
WHEN C_VENTAS%ROWCOUNT
C_VENTAS%ROWCOUNT >> 55
OR
OR C_VENTAS%NOTFOUND;
C_VENTAS%NOTFOUND;
END LOOP;
END LOOP;
CLOSE
CLOSE C_VENTAS;
C_VENTAS;
END;
END;

Facultad Politécnica Base de Datos II 16


Cursor con Parámetros: Sintaxis

 Pase valores de los parámetros a un cursor cuando


el cursor se abre y se ejecuta el query

CURSOR
CURSOR nombre_cursor
nombre_cursor
[(nombre_parametro tipo_dato, ...)]
[(nombre_parametro tipo_dato, ...)]
IS
IS
sentencia_select;
sentencia_select;

 Esto le permite abrir un cursor explícito varias veces


con un conjunto activo diferente cada vez

Facultad Politécnica Base de Datos II 17


Cursor con Parámetros: Ejemplo

Pase el id de departamento y cargo a la cláusula


WHERE.

DECLARE
DECLARE
CURSOR
CURSOR C_VENTAS(P_ID
C_VENTAS(P_ID NUMBER)
NUMBER) IS
IS
SELECT
SELECT v.id_articulo,
v.id_articulo, a.nombre,
a.nombre, v.cantidad
v.cantidad
FROM
FROM b_Detalle_ventas
b_Detalle_ventas v,v, b_articulos
b_articulos aa
WHERE
WHERE a.id
a.id == v.id_articulo
v.id_articulo AND
AND
v.
v. id_venta
id_venta == P_ID;
P_ID;
R_VENTAS
R_VENTAS C_VENTAS%ROWTYPE;
C_VENTAS%ROWTYPE;

BEGIN
BEGIN
OPEN
OPEN C_VENTAS(1);
C_VENTAS(1);

Facultad Politécnica Base de Datos II 18


Cursor FOR Loop: Sintaxis

• En los cursores FOR LOOP, las sentencias OPEN, FETCH y


CLOSE son implícitas

FOR nombre_registro IN
FOR nombre_registro nombre_cursor LOOP
IN nombre_cursor LOOP
sentencia1;
sentencia1;
sentencia2;
sentencia2;
.. .. ..
END
END LOOP;
LOOP;

• NO SE DECLARA EL REGISTRO QUE CONTROLA EL


LOOP. Su ámbito es solo el del LOOP y por tanto se declara
automáticamente

Facultad Politécnica Base de Datos II 19


Cursor FOR Loop: Ejemplo
Recupere todos los artículos vendidos en una fecha dada.
DECLARE
DECLARE
CURSOR
CURSOR C_VENTAS
C_VENTAS IS
IS
SELECT
SELECT v.id_articulo,
v.id_articulo, a.nombre,
a.nombre, v.cantidad
v.cantidad
FROM
FROM b_Detalle_ventas
b_Detalle_ventas vv JOIN
JOIN b_Ventas
b_Ventas cc
ON
ON c.id
c.id == v.id_venta
v.id_venta JOIN
JOIN b_articulos
b_articulos aa
ON
ON a.id
a.id == v.id_articulo
v.id_articulo
WHERE
WHERE TRUNC(c.fecha)
TRUNC(c.fecha) == TO_DATE('02/01/2011','DD/MM/YYYY');
TO_DATE('02/01/2011','DD/MM/YYYY');
BEGIN
BEGIN
FOR
FOR R_VENTAS
R_VENTAS IN
IN C_VENTAS
C_VENTAS LOOP
LOOP --
-- No
No hacer
hacer OPEN
OPEN ni
ni FETCH!!
FETCH!!
DBMS_OUTPUT.PUT_LINE
DBMS_OUTPUT.PUT_LINE (R_VENTAS.NOMBRE||'-
(R_VENTAS.NOMBRE||'-
'||TO_CHAR(R_VENTAS.CANTIDAD,
'||TO_CHAR(R_VENTAS.CANTIDAD, '999G999'));
'999G999'));
END
END LOOP;
LOOP; --No
--No hacer
hacer el
el CLOSE
CLOSE
END;
END;

Facultad Politécnica Base de Datos II 20


Cursor FOR LOOP utilizando Subqueries

Recupere artículos para una orden de


p_proyecto_suministro, uno por uno, hasta que no existan
más artículos:

FOR
FOR rec_item
rec_item IN
IN (select
(select id,
id, nombre
nombre from
from b_articulos
b_articulos
where
where stock_actual
stock_actual << stock_minimo)
stock_minimo) LOOP
LOOP

END
END LOOP;
LOOP; --
-- CLOSE
CLOSE implícito
implícito

Facultad Politécnica Base de Datos II 21


Cláusula WHERE CURRENT OF

 Permite ACTUALIZAR o BORRAR una fila del propio


cursor
 Al incluir la sentencia FOR UPDATE, Oracle llavea el
conjunto a ser recuperado

SELECT...FROM...FOR
SELECT...FROM...FOR UPDATE
UPDATE [OF columna ][NOWAIT]
[OF columna ][NOWAIT]

 La fila actual de un cursor explícito es referida usando


la cláusula WHERE CURRENT OF

Facultad Politécnica Base de Datos II 22


Cláusula WHERE CURRENT OF
Ejemplo

DECLARE
DECLARE
……
CURSOR
CURSOR C_ARTICULOS
C_ARTICULOS ISIS
SELECT
SELECT ** FROM
FROM B_ARTICULOS
B_ARTICULOS FOR
FOR UPDATE;
UPDATE;
BEGIN
BEGIN
FOR
FOR REC_ART
REC_ART IN
IN C_ARTICULOS
C_ARTICULOS LOOOP
LOOOP
UPDATE
UPDATE B_ARTICULOS
B_ARTICULOS
SET
SET PRECIO
PRECIO :=
:= ROUND(PRECIO
ROUND(PRECIO ** 1,03)
1,03)
WHERE
WHERE CURRENT
CURRENT OFOF C_ARTICULOS;
C_ARTICULOS;
END
END LOOP;
LOOP;
COMMIT;
COMMIT;
END;
END;

Facultad Politécnica Base de Datos II 23