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 <lista> FROM <tabla> ). PL/SQL utiliza cursores para gestionar las instrucciones SELECT. Un cursor es un conjunto de registros devuelto por una instrucción SQL.



Índice

Podemos distinguir dos tipos de cursores:

Un cursor se define como cualquier otra variable de PL/SQL y debe nombrarse de acuerdo a los mismos convenios que cualquier otra variable.

Los cursores implícitos se utilizan para realizar consultas SELECT que devuelven un único registro. Deben tenerse en cuenta los siguientes puntos cuando se utilizan cursores implícitos:

SET SERVEROUTPUT ON;
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;

Para procesar instrucciones SELECT que devuelvan más de una fila, son necesarios cursores explícitos combinados con una estructura de bloque. A partir de ahora, cuando hagamos referencia a cursores nos referiremos a cursores explícitos.

Para trabajar con un cursor hay que realizar los siguientes pasos:

  1. Declarar el cursor
  2. Abrir el cursor en el servidor
  3. Recuperar cada una de sus filas (bucle)
  4. Cerrar el cursor

1. Declarar el cursor

Al igual que cualquier otra variable, el cursor se declara en la sección DECLARE. Se define el nombre que tendrá el cursor y qué consulta SELECT ejecutará. No es más que una declaración. La sintaxis básica es:

CURSOR nombre_cursor IS instrucción_SELECT
CURSOR nombre_cursor(param1 tipo1, ..., paramN tipoN) IS instrucción_SELECT

Una vez que el cursor está declarado ya podrá ser utilizado dentro del bloque de código.

Antes de utilizar un cursor se debe abrir. En ese momento se ejecuta la sentencia SELECT asociada y se almacena el resultado en el área de contexto (estructura interna de memoria que maneja el cursor). Un puntero señala a la primera fila

2. Abrir el cursor

Al abrir el cursor se ejecuta la sentencia SELECT asociada y cuyo resultado se guarda en el servidor en un área de memoria interna (tablas temporales) de las cuales se va retornando cada una de las filas según se va pidiendo desde el cliente. Al abrir un cursor, un puntero señalará al primer registro.

La sintaxis de apertura de un cursor es:

OPEN nombre_cursor;
OPEN nombre_cursor(valor1, valor2, ..., valorN);

Una vez que el cursor está abierto, se podrá empezar a pedir los resultados al servidor.

3.Recuperar cada una de sus filas.

Una vez que el cursor está abierto en el servidor se podrá hacer la petición de recuperación de fila. En cada recuperación solo se accederá a una única fila. La sintaxis de recuperación de fila de un cursor es:

FETCH nombre_cursor INTO variables;

Podremos recuperar filas mientras la consulta SELECT tenga filas pendientes de recuperar. Para saber cuándo no hay más filas podemos consultar los siguientes atributos de un cursor:

Al recuperar un registro, la información recuperada se guarda en una o varias variables. Si sólo se hace referencia a una variable, ésta se puede declarar con %ROWTYPE. Si se utiliza una lista de variables, cada variable debe coincidir en tipo y orden con cada una de las columnas de la sentencia SELECT.

Así lo acción más típica es recuperar filas mientras queden alguna por recuperar en el servidor. Esto lo podremos hacer a través de los siguientes bloques:

OPEN nombre_cursor;
LOOP
  FETCH nombre_cursor INTO variables;
  EXIT WHEN nombre_cursor%NOTFOUND;
  --procesar cada una de las filas
END LOOP;
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;

FOR variable IN nombre_cursor LOOP
  /* Procesamiento de los registros recuperados */
END LOOP;

4. Cerrar el cursor

Una vez que se han recuperado todas las filas del cursor, hay que cerrarlo para que se liberen de la memoria del servidor los objetos temporales creados. Si no cerrásemos el cursor, la tabla temporal quedaría en el servidor almacenada con el nombre dado al cursor y la siguiente vez ejecutásemos ese bloque de código, nos daría la excepción CURSOR_ALREADY_OPEN (cursor ya abierto) cuando intentásemos abrir el cursor. Para cerrar el cursor se utiliza la siguiente sintaxis:

CLOSE numbre_cursor;

Cuando trabajamos con cursores debemos considerar:

Atributos en cursores implícitos

Los cursores implícitos no se pueden manipular por el usuario, pero Oracle sí permite el uso de sus atributos. Las sentencia a través de las que podemos obtener información de estos atributos son: SELECT ... INTO, [INSERT, UPDATE, DELETE]3.

En este caso, se debe anteponer al nombre del atributo el prefijo SQL, en lugar del nombre del cursor.

Ejemplos:

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;
  DBMS_OUTPUT.PUT_LINE(continente);
  CLOSE cpaises;
END;
DECLARE
  CURSOR cpaises IS
  SELECT CO_PAIS, DESCRIPCION, CONTINENTE FROM PAISES;
  registro cpaises%ROWTYPE;
BEGIN
  OPEN cpaises;
  FETCH cpaises INTO registro;
  DBMS_OUTPUT.PUT_LINE(continente);
  CLOSE cpaises;
END;
DECLARE
  r ARTICULOS%ROWTYPE;
BEGIN
  FOR r IN ( SELECT * FROM ARTICULOS ) LOOP
    DBMS_OUTPUT.PUT_LINE(r.cArtDsc);
  END LOOP;
END;
BEGIN
  UPDATE ARTICULOS SET cArtDsc = `Pantalla LCD’ WHERE cCodArt = ‘LCD’;
  IF SQL%NOTFOUND THEN -- Otra opción : SQL%ROWCOUNT = 0
    INSERT INTO ARTICULOS (cCodArt,cDesArt)
    VALUES (‘LCD’,’Pantalla LCD’);
  END IF;
END;

Cursores Parametrizados

Los cursores son aquellos que permiten utilizar la orden OPEN para pasarle al cursor el valor de uno o varios de sus parámetros.

DECLARE
  CURSOR cArt (cFml Articulos.cArtFml%TYPE)
    IS SELECT cArtCdg,cArtDsc FROM Articulos WHERE cArtFml = cFml;
  xCod Articulos.cArtCdg%TYPE;
  xDes Articulos.cArtDsc%TYPE;
BEGIN
  OPEN cArt('F1');
  LOOP
    FETCH cArt INTO xCod,xDes;
    EXIT WHEN cArt%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE (xDes);
  END LOOP;
  CLOSE cArt;
END;

Cursores de actualización

Los cursores de actualización se declaran igual que los cursores explícitos, añadiendo FOR UPDATE al final de la sentencia SELECT.

CURSOR nombre_cursor IS instrucción_SELECT FOR UPDATE

Para actualizar los datos del cursor hay que ejecutar una sentencia UPDATE especificando la cláusula WHERE CURRENT OF <cursor_name>.

UPDATE <nombre_tabla> SET <campo_1> = <valor_1>[,<campo_2> = <valor_2>]
WHERE CURRENT OF <cursor_name>

Cuando trabajamos con cursores de actualización debemos tener en cuenta que la sentencia UPDATE genera bloqueos en la base de datos ( transacciones, disparadores,etc).

DECLARE
  CURSOR cpaises IS
   select CO_PAIS, DESCRIPCION, CONTINENTE from paises
  FOR UPDATE;
  co_pais VARCHAR2(3);
  descripcion VARCHAR2(50);
  continente VARCHAR2(25);
BEGIN
  OPEN cpaises;
  FETCH cpaises INTO co_pais,descripcion,continente;
  WHILE cpaises%found
    LOOP
      UPDATE PAISES SET CONTINENTE = CONTINENTE || '.'
      WHERE CURRENT OF cpaises;
      FETCH cpaises INTO co_pais,descripcion,continente;
    END LOOP;
  CLOSE cpaises;
  COMMIT;
END;

Siguiente tema: PL/SQL - Procedimientos y Funciones