Cuando una consulta devuelve múltiples filas, podemos 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 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.
BEGIN
...
OPEN cFamilias;
LOOP
FETCH cFamilias INTO mi_id, mi_nom, mi_fam, mi_ofi;
EXIT WHEN cFamilias%NOTFOUND;
...
END LOOP;
...
END;
Una vez procesado el cursor, deberemos cerrarlo, con lo que desabilitamos el cursor y el conjunto resultado queda indefinido.
Una vez cerrado el cursor podemos reabrirlo, pero cualquier otra operación que hagamos con el cursor cerrado lanzará la excepción INVALID_CURSOR.
También podemos simplificar la operación de procesamiento de un cursor, por medio de los bucles para cursores, los cuales declaran implícitamente una variable índice definida como %ROWTYPE para el cursor, abren el cursor, se van trayendo 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;