MUNDORACLE

LUGAR DODE SE RECOGE TODO LO RELACIONADO CON ORACLE : HISTORIA, ADMINISTRACION Y PROGRAMACION.

sábado, 20 de diciembre de 2014

CURSORES EN PL/SQL

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_FOUNDSe produce cuando una sentencia SELECT intenta  recuperar datos pero ninguna fila satisface sus condiciones. Es decir, cuando "no hay datos"
TOO_MANY_ROWSDado 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:
  CLOSE nombre_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