cursores-pl-sql
Francisco Herrera

Francisco Herrera

Business Intelligence Consultant | Data Specialist

Otros Artículos:

Cursores PL/SQL

Compartir en linkedin
LinkedIn
Compartir en facebook
Facebook
Compartir en twitter
Twitter
Compartir en whatsapp
WhatsApp

Un cursor PL/SQL se utiliza básicamente para manejar sentencias “SELECT” de varios registros.

En términos generales, los cursores están formados por un conjunto de registros devueltos por dicho SELECT.

Si lo miramos desde el punto de vista operativo de Oracle, que es la principal tecnología que se sirve del lenguaje PL/SQL, dichos cursores corresponden a segmentos de memoria (normalmente tablas temporales) utilizados para operar con los registros devueltos por la sentencia SELECT, es decir, segmentos que contienen la información correspondiente a la ejecución de dicha sentencia.

cursores

Sintetizando, un cursor va a actuar como una especie de loop que recorrerá la consulta especificada fila por fila, retornándonos el valor que se haya indicado en dicha consulta, almacenando estos valores en tablas temporales (que, como veremos más adelante, se abrirán y se cerrarán al ejecutar el cursor) y, previa indicación en la sentencia, nos devolverá una lista de valores. Más adelante veremos esto de manera más detallada.

Podemos diferenciar dos tipos de cursores, los implícitos y los explícitos:

CURSORES IMPLÍCITOS

Los cursores implícitos son aquellos que nos devuelven un solo registro al ejecutar la sentencia SELECT. Los utilizamos típicamente para operaciones tipo SELECT … INTO. Los llamamos implícitos porque ya son definidos de manera intrínseca por el propio PL/SQL y no hace falta declararlos mediante la sentencia “CURSOR”, la cual define que la variable que estamos creando es un cursor. Por ejemplo:

				
					SET SERVEROUTPUT ON;
declare
  vdescripcion VARCHAR2(50);
begin
  SELECT DESCRIPCION INTO vdescripcion from ALUMNOS WHERE CURSO_ALU = '4º';
  dbms_output.put_line('La lectura del cursor es: ' || vdescripcion);
end;

				
			

En la anterior sentencia, como vemos, simplemente declaramos una variable que va a ser la descripción, ejecutamos un SELECT … INTO que va a meter dentro del valor de la variable la consulta correspondiente a la descripción del alumno donde el código es el 4º curso e imprimirá el resultado único mediante la sentencia dbms_output.put_line.

				
					DECLARE
       lsalario empleados.salario%TYPE;
       ldni empleados.dni%TYPE;
     BEGIN
       SELECT salario, dni
       INTO lsalario, ldni
       FROM empleados
       WHERE nombre = 'Jose'
       AND apellidos = 'Antunez Puntos';
       /* Resto de sentencias del bloque */
     END;
				
			

En este ejemplo, recibiremos como output las variables salario y dni del empleado.

A parte de lo mencionado anteriormente, cuando usamos cursores implícitos debemos tener en cuenta varias cosas. Por ejemplo, es importante que la variable declarada tenga exactamente el mismo tipo de dato que la columna llamada en la tabla. Es decir, no podemos declarar una variable tipo FLOAT que reciba valores tipo CHAR, etc., ya que esto haría saltar un error en la consulta. Solemos anticiparnos a ese error añadiendo %TYPE al final de la declaración de la variable, de manera que PL/SQL asigne el tipo de la variable a su tipo de origen. 

Importante también es destacar que si tenemos un cursor abierto y los datos de origen cambian, esto no se verá reflejado en el cursor hasta cerrarlo y ejecutarlo de nuevo.

Por otro lado, como los cursores implícitos solo pueden devolver una fila, si la consulta devuelve ninguna o más de una, nos devolverá una verificación de excepción; en el primer caso, encontraremos NO_DATA_FOUND y en el segundo TOO_MANY_ROWS.

Normalmente suelen usarse más a menudo los cursores implícitos, ya que son más rápidos de procesar y su codificación es más limpia que con los explícitos. Recordemos que PL/SQL es un lenguaje interpretado, lo cual quiere decir que su procesamiento va línea por línea. 

Esto se traduce de una manera simple, a menos líneas, menos tiempo total de procesamiento. Sin embargo, en el caso de que una query falle a la hora de buscar un registro, el cursor explícito es más eficiente, ya que al declarar el cursor se evita que aparezcan excepciones, y en PL/SQL el manejo de excepciones es relativamente costoso.

CURSORES EXPLÍCITOS

Si queremos que una consulta nos devuelva más de una fila, debemos generar un bloque de código que incluya la definición previa de la variable CURSOR, lo cual se conoce también como cursor explícito

La metodología se sigue a través de 4 pasos; declarar el cursor, abrirlo con la instrucción OPEN, leer cada una de las filas de la consulta con FETCH y cerrarlo mediante la instrucción CLOSE:

– Declaración del cursor:

Como el resto de variables, el cursor se va a declarar a través de la sección DECLARE. Tras esto, definiremos el nombre que tendrá el cursor y la consulta que va a ejecutar a través de la cláusula SELECT. Por ejemplo:

				
					CURSOR nombre_cursor IS instrucción_SELECT

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

– Abrir el cursor:

La apertura del cursor a través de la cláusula OPEN hará que se ejecute y se guarde la consulta temporal en nuestro servidor. La sintaxis para abrir el cursor es como sigue:

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

– Recuperar las filas de la consulta:

La recuperación de las filas ocurre de manera individual, es decir, cada recuperación del cursor accederá a una única fila. Una vez abierto el cursor, irá devolviendo las diferentes filas consultadas empezando desde el primer registro (por ello debemos crear un bucle LOOP que recupere todas automáticamente). 

La sintaxis de recuperación va acompañada de la sentencia FETCH, la cual coloca el cursor en la siguiente fila de la tabla temporal y asigna los valores a las variables de destino:

				
					FETCH nombre_cursor INTO variables;
				
			

Y con bucle:

				
					OPEN nombre_cursor;
LOOP
  FETCH nombre_cursor INTO variables;
  EXIT WHEN nombre_cursor%NOTFOUND;
END LOOP;
				
			

Dicha sentencia nos permitirá recuperar filas hasta que ya no queden registros que recuperar a través de la condición ‘WHEN … y el atributo %NOTFOUND’, la cual simplemente para el loop cuando no encuentra más datos que añadir. 

Otro ejemplo es con la condición ‘WHILE … %FOUND’, que nos devolverá resultado “mientras encuentre” datos datos disponibles:

				
					OPEN nombre_cursor;
FETCH nombre_cursor INTO lista_variables;
WHILE nombre_cursor%FOUND
LOOP
  FETCH nombre_cursor INTO lista_variables;
END LOOP;
				
			

También podemos usar un bucle FOR, lo cual constituye la manera más simple:

				
					FOR variable IN nombre_cursor LOOP
END LOOP;
				
			

Sin embargo dada las características de la sentencia, como habrás adivinado si has estado atent@, este tipo de cursor entra dentro de la categoría de los implícitos, ya que no se declara el cursor per sé y se ejecutan las instrucciones OPEN, FETCH y CLOSE de manera implícita.

ATRIBUTOS DE LOS CURSORES

El cursor nos permitirá comprobar el resultado de la lectura en base al atributo que le asignemos, antes vimos %NOTFOUND y %FOUND, ampliemos un poco más esto:

%FOUND: nos devolverá TRUE si la última fila que procesa el cursor contiene datos. También nos devolverá TRUE si al hacer INSERT, DELETE o UPDATE estos afectan a alguna fila. 

 

%NOTFOUND: nos devolverá TRUE si la última fila que procesa el cursor no contiene ningún dato. También nos devolverá TRUE si al hacer INSERT, DELETE o UPDATE estos no afectan a ninguna fila.

 

%ROWCOUNT: Devolverá el número de filas afectadas por los comandos DML o bien las filas devueltas por la sentencia SELECT.

 

%ISOPEN: Para los cursores implícitos siempre devolverá FALSE, ya que Oracle los cierra automáticamente al ejecutar el SELECT, sin embargo puede resultar de utilidad para saber si hemos cerrado correctamente un cursor explícito.

En conclusión, siempre y cuando no estemos hablando de consultas de millones de entradas, donde la eficiencia se puede ver muy comprometida por el propio funcionamiento iterativo del lenguaje PL/SQL, un cursor es una buena idea si queremos actualizar, borrar, etc., múltiples registros de una tabla. Además es una buena manera de obtener una consulta de múltiples registros de una tabla manera rápida y sencilla.  

Sin embargo, es muy importante si se abre un cursor, cerrarlo, pues como una vez leí en el maravilloso StackOverFlow “Un cursor abierto es como mantener abierta la puerta de la nevera, no debes hacerlo durante horas si no es necesario, pero eso no quiere decir que no debas abrirla nunca”.

Fuentes

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Business Data Master Logo

No te pierdas el

WEBINAR
Gratuito

Explicaremos en detalle los contenidos y objetivos del Business Data Master

29/11/2021

18:30 (GTM+1)

Online

BUSINESS DATA MASTER

* Tu información será utilizada exclusivamente para contactarte en relación al Business Data Master. No hacemos spam ni compartimos datos con terceros.