No es un bug, es una característica no documentada

lunes, 16 de marzo de 2015

Bases de datos. SQL programado (VI). Cursores

9:24 Posted by Inazio , No comments

Cursores

Un cursor es una zona de memoria donde yo me traigo una zona de memoria para trabajar con ellas.

¿Cómo se declara?


DECLARE nombreCursor for sentenciaSQL;

Es decir, un ejemplo sería


Sería como recorrer un fichero secuencial, o al menos es el símil más parecido que se me ocurre.
La idea de los cursores se crea para poder trabajar fila a fila con un conjunto de filas seleccionadas.

Es decir, se abre, se trabaja y se cierra el cursor. Exactamente como un fichero secuencial.

En el ejemplo anterior creo un cursor con las dos primeras filas de la tabla alumnos.

¿Qué es lo que hace este cursor?

Con open c_alumnos abro el cursor posicionandolo delante de las dos filas llamadas, es decir, al principio de id 1


También tengo declaradas dos variables, v_id y v_alumno, donde almacenaremos los datos que leo para trabajar con ellos en la variable.

Para eso uso la función FETCH.
La sentencia sería

FETCH nombreCursor INTO variableDondeGuardar;

En este caso, almacenando el campo id en v_id, y el campo alumno en v_alumno.

Es decir, en este caso las variables pasan a valer, hasta la siguiente lectura:
  • v_id = 1
  • v_alumno = ALUMNO1
y una vez realizado este "almacenamiento", procedo al tratado de datos. En este caso solo los muestro por pantalla, bueno, pero por algo se empieza.

Llego al final del bucle y vuelvo a realizar otro FETCH, en el que las variables pasan a valer
  • v_id = 2
  • v_alumno = ALUMNO2
Repetimos los pasos y vuelve a realizar el FETCH, pero este FETCH va a fallar. Va a leer un final de fichero, con lo que saldrá un error 1329 (NO DATA). Sale del bucle, sí, pero no son trazas...

¿Cómo se controla el error NO DATA?

Lo arreglamos usando un manejador de errores. ¿Cómo? Declarandolo después del cursor, tal que así

DECLARE CONTINUE HANDLER FOR NOT FOUND SET variable = 1;

Y previamente habiendo declarando la variable con valor por defecto a 0

DECLARE v_ultima_fila int default 0;

De momento sólo trataremos el error 1329, o lo que es lo mismo, al error NOT FOUND.

Nuestro programa quedaría


¿Y que va a hacer entonces este control de errores?

Sabemos que el FETCH llegará un momento que fallará, porque intentará leer un final de fichero.
Automaticamente, cuando pete esta sección, saltará el controlador de errores y realizará la acción que está programada, cambiar el valor de la variable de 0 a 1, y posteriormente continuará por la siguiente linea donde se produjo el error (para eso está CONTINUE HANDLER).

Si falló en la linea 16, pasamos a la 17, donde creamos una condición en la que si la variable usada por el controlador de errores vale 1, le damos salida al bucle con 

LEAVE nombreDelBucle;

Realizando una traza del programa, los valores de las variables serían las siguientes


Y posteriormente, cerraremos el cursor con 

CLOSE nombreCursor;

Veamos otro ejemplo


¿Que diferencia hay entre este programa y el anterior?

Bueno, basicamente que le estoy pasando el parametro para usar en el cursor por parámetro. Me explico, para la consulta, en el where, en vez de decirle que id sea menor o igual a 2, le indico que sea menor o igual al dato que le paso al llamar al procedimiento.

Cursores anidados

O lo que es lo mismo, un cursor dentro de otro cursor. Veamos este ejemplo


Lo subrayado en amarillo son los dos cursores que estoy creando.

Lo que hará este programa, nuevamente, sería como realizar el ejercicio de la loteria, que lo podéis consultar en la sección de El manual.

La idea abrir el cursor que consideraremos principal, c_centros, y lo recorro en un bucle, dentro del cual abriré el segundo cursor, c_departamentos.

Una vez obtenida la información deseada, por ejemplo el número y nombre del centro con id 10 (es un decir) y el nombre de sus departamentos, ya podremos realizar las operaciones que deseemos. En este caso, mostrarla por pantalla.

Por supuesto, tengo dos finales de fichero y un solo controlador, con lo cual tengo que tener mucho cuidado. Para realizar un control correcto, está la linea 38, en la que reinicio la variable del contador a 0 de nuevo, después de haber recorrido el cursor interno.

Realizando una traza con dos centros y dos departamentos por cada centro, las variables

0 comentarios:

Publicar un comentario