Cuando una consulta devuelve múltiples filas, debemos declarar explícitamente un cursor para procesar las filas devueltas. Cuando declaramos un cursor, lo que hacemos es darle un nombre y asociarle una consulta usando la siguiente sintaxis:
CURSOR nombre_cursor [(parametro [, parametro] ...)] [RETURN tipo_devuelto] IS sentencia_select;
Donde tipo_devuelto
debe representar un registro o una fila de una tabla de la base de datos, y parámetro
sigue la siguiente sintaxis:
parametro := nombre_parametro [IN] tipo_dato [{:= | DEFAULT} expresion]
Ejemplos:
CURSOR cAgentes IS SELECT * FROM agentes;
CURSOR cFamilias RETURN familias%ROWTYPE IS SELECT * FROM familias WHERE ...
Además, como hemos visto en la declaración, un cursor puede tomar parámetros, los cuales pueden aparecer en la consulta asociada como si fuesen constantes. Los parámetros serán de entrada, un cursor no puede devolver valores en los parámetros actuales. A un parámetro de un cursor no podemos imponerle la restricción NOT NULL
.
CURSOR c1 (cat INTEGER DEFAULT 0) IS SELECT * FROM agentes WHERE categoria = cat;
Cuando abrimos un cursor, lo que se hace es ejecutar la consulta asociada e identificar el conjunto resultado, que serán todas las filas que emparejen con el criterio de búsqueda de la consulta. Para abrir un cursor usamos la sintaxis:
OPEN nombre_cursor [(parametro [, parametro] ...)];
Ejemplos:
OPEN cAgentes;
OPEN c1(1);
OPEN c1;
La sentencia FETCH
devuelve una fila del conjunto resultado. Después de cada FETCH
, el cursor avanza a la próxima fila en el conjunto resultado.
FETCH cFamilias INTO mi_id, mi_nom, mi_fam, mi_ofi;
Para cada valor de columna devuelto por la consulta SELECT
asociada al cursor, debe haber una variable que se corresponda en la lista de variables después del INTO
.
Para procesar un cursor entero deberemos hacerlo por medio de un bucle.
Hay varias formas de hacerlo. En el formato del ejemplo siguiente es necesario abrir el cursor previamente y tras recorrerlo cerrarlo.
BEGIN
...
OPEN cFamilias;
LOOP
FETCH cFamilias INTO mi_id, mi_nom, mi_fam, mi_ofi;
EXIT WHEN cFamilias%NOTFOUND;
...
END LOOP;
CLOSE cFamilias;
...
END;
Una vez cerrado el cursor podemos reabrirlo, pero cualquier otra operación que hagamos con el cursor cerrado lanzará la excepción INVALID_CURSOR
.
Otra forma más sencilla es utilizar los bucles para cursores, los cuales declaran implícitamente una variable índice definida como %ROWTYPE
para el cursor, abren el cursor, extraen los valores de cada fila del cursor, almacenándolas en la variable índice, y finalmente cierran el cursor.
BEGIN
...
FOR cFamilias_rec IN cFamilias LOOP
--Procesamos las filas accediendo a
--cFamilias_rec.identificador, cFamilias_rec.nombre,
--cFamilias_rec.familia, ...
END LOOP;
...
END;