Un cursor es el nombre para un área memoria privada que contiene información procedente de la ejecución de una sentencia SELECT. Cada cursor tiene unos atributos que nos devuelven
información útil sobre el estado del cursor en la ejecución de la sentencia SQL. Cuando un cursor está abierto y los datos referenciados por la consulta SELECT cambian, estos cambios no son recogidos por el cursor.
PL/SQL crea implícitamente un cursor para
todas las sentencias SQL de manipulación de datos sobre un conjunto de filas, incluyendo aquellas que solo devuelven una sola fila.
En PL/SQL
no se pueden utilizar sentencias SELECT de sintaxis básica ( SELECT
FROM ). PL/SQL utiliza cursores para gestionar las instrucciones SELECT. Un cursor es un conjunto de registros devuelto por una instrucción SQL.
Podemos distinguir dos tipos de cursores:
- Cursores implícitos. Este tipo de cursores se utiliza para operaciones SELECT INTO. Se usan cuando la consulta devuelve un único registro.
- Cursores explícitos. Son los cursores que son declarados y controlados por el programador. Se utilizan cuando la consulta devuelve un conjunto de registros. Ocasionalmente también se utilizan en consultas que devuelven un único registro por razones de eficiencia. Son más rápidos.
Cursores Implicitos
Declaración de cursores implicitos.
Los cursores implicitos se utilizan para realizar consultas SELECT que devuelven un único registro.
Deben tenerse en cuenta los siguientes puntos cuando se utilizan cursores implicitos:
- Con cada cursor implicito debe existir la palabra clave INTO.
- Las variables que reciben los datos devueltos por el cursor tienen que contener el mismo tipo de dato que las columnas de la tabla.
- Los cursores implicitos solo pueden devolver una única fila. En caso de que se devuelva más de una fila (o ninguna fila) se producirá una excepcion. No se preocupe si aún no sabe que es una excepcion, le valdrá conocer que es el medio por el que PL/SQL gestiona los errores.
El siguiente ejemplo muestra un cursor implicito:
declare
vdescripcion VARCHAR2(50);
begin SELECT DESCRIPCION
INTO vdescripcion
from PAISES
WHERE CO_PAIS = 'ESP';
dbms_output.put_line('La lectura del cursor es: ' || vdescripcion);
end;
|
La salida del programa generaría la siguiente línea:
La lectura del cursor es: ESPAÑA
Excepciones asociadas a los cursores implicitos.
|
Los cursores implicitos sólo pueden devolver una fila, por lo que pueden producirse determinadas excepciones. Las más comunes que se pueden encontrar son no_data_found y too_many_rows. La siguiente tabla explica brevemente estas excepciones.
Excepcion
|
Explicacion
|
| NO_DATA_FOUND | Se produce cuando una sentencia SELECT intenta recuperar datos pero ninguna fila satisface sus condiciones. Es decir, cuando "no hay datos" |
| TOO_MANY_ROWS | Dado que cada cursor implicito sólo es capaz de recuperar una fila , esta excepcion |
Cursores Explicitos en PL/SQL
Declaración de cursores explicitos
Los cursores explicitos se emplean para realizar consultas SELECT que pueden devolver cero filas, o más de una fila.
Para trabajar con un cursor explicito necesitamos realizar las siguientes tareas:
- Declarar el cursor.
- Abrir el cursor con la instrucción OPEN.
- Leer los datos del cursor con la instrucción FETCH.
- Cerrar el cursor y liberar los recursos con la instrucción CLOSE.
Para declarar un cursor debemos emplear la siguiente sintaxis:
CURSOR nombre_cursor IS
instrucción_SELECT
|
También debemos declarar los posibles parametros que requiera el cursor:
CURSOR nombre_cursor(param1 tipo1, ..., paramN tipoN) IS
instrucción_SELECT
|
Para abrir el cursor
OPEN nombre_cursor;
o bien (en el caso de un cursor con parámetros)
OPEN nombre_cursor(valor1, valor2, ..., valorN);
|
Para recuperar los datos en variables PL/SQL.
FETCH nombre_cursor INTO lista_variables;
-- o bien ...
FETCH nombre_cursor INTO registro_PL/SQL;
|
Para cerrar el cursor:
El siguiente ejemplo ilustra el trabajo con un cursor explicito. Hay que tener en cuenta que al leer los datos del cursor debemos hacerlo sobre variables del mismo tipo de datos de la tabla (o tablas) que trata el cursor.
DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
CLOSE cpaises;
END;
|
Podemos simplificar el ejemplo utilizando el atributo de tipo %ROWTYPE sobre el cursor.
DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
registro cpaises%ROWTYPE;
BEGIN
OPEN cpaises;
FETCH cpaises INTO registro;
CLOSE cpaises;
END;
|
El mismo ejemplo, pero utilizando parámetros:
DECLARE
CURSOR cpaises (p_continente VARCHAR2)
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES
WHERE CONTINENTE = p_continente;
registro cpaises%ROWTYPE;
BEGIN
OPEN cpaises('EUROPA');
FETCH cpaises INTO registro;
CLOSE cpaises;
END;
|
Cuando trabajamos con cursores debemos considerar:
- Cuando un cursor está cerrado, no se puede leer.
- Cuando leemos un cursor debemos comprobar el resultado de la lectura utilizando los atributos de los cursores.
- Cuando se cierra el cursor, es ilegal tratar de usarlo.
- Es ilegal tratar de cerrar un cursor que ya está cerrado o no ha sido abierto
Atributos en cursores
- SQL%NOTFOUND devuelve TRUE cuando la última sentencia SELECT no recuperó ninguna fila, o cuando INSERT, DELETE o UPDATE no afectan a ninguna fila
- SQL%FOUND devuelve TRUE cuando la última sentencia SELECT devuelve alguna fila, o cuando INSERT, DELETE o UPDATE afectan a alguna fila
- SQL%ROWCOUNT devuelve el número de filas afectadas por INSERT, DELETE o UPDATE o las filas devueltas por una sentencia SELECT
- SQL%ISOPEN siempre devuelve FALSE, porque Oracle cierra automáticamente el cursor implícito cuando termina la ejecución de la sentencia
Manejo del cursor
Por medio de ciclo LOOP podemos iterar a través del cursor. Debe tenerse cuidado de agregar una condición para salir del bucle:
Vamos a ver varias formas de iterar a través de un cursor. La primera es utilizando un bucle LOOP con una sentencia EXIT condicionada:
OPEN nombre_cursor;
LOOP
FETCH nombre_cursor INTO lista_variables;
EXIT WHEN nombre_cursor%NOTFOUND;
/* Procesamiento de los registros recuperados */
END LOOP;
CLOSE nombre_cursor;
|
Aplicada a nuestro ejemplo anterior:
DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
LOOP
FETCH cpaises INTO co_pais,descripcion,continente;
EXIT WHEN cpaises%NOTFOUND;
dbms_output.put_line(descripcion);
END LOOP;
CLOSE cpaises;
END;
|
Otra forma es por medio de un bucle WHILE LOOP. La instrucción FECTH aparece dos veces.
OPEN nombre_cursor;
FETCH nombre_cursor INTO lista_variables;
WHILE nombre_cursor%FOUND
LOOP
/* Procesamiento de los registros recuperados */
FETCH nombre_cursor INTO lista_variables;
END LOOP;
CLOSE nombre_cursor;
|
DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
WHILE cpaises%found
LOOP
dbms_output.put_line(descripcion);
FETCH cpaises INTO co_pais,descripcion,continente;
END LOOP;
CLOSE cpaises;
END;
|
Por último podemos usar un bucle FOR LOOP. Es la forma más corta ya que el cursor es implicitamente se ejecutan las instrucciones OPEN, FECTH y CLOSE.
FOR variable IN nombre_cursor LOOP
/* Procesamiento de los registros recuperados */
END LOOP;
|
BEGIN
FOR REG IN (SELECT * FROM PAISES)
LOOP
dbms_output.put_line(reg.descripcion);
END LOOP;
END;
|
|
No hay comentarios:
Publicar un comentario