Listado: CURSOR.
Una rutina de listado realiza un CURSOR a una tabla para recuperar todos los registros que cumplan una determinada condición.
Nuestra rutina devolverá la información recuperada al programa llamante a través de una tabla interna definida en la linkage. Esta tabla tendrá un número de ocurrencias OCCURS que puede ser menor que el número de registros recuperados por el cursor.
Tendremos que tener en cuenta todo esto a la hora de codificar el programa.
Vamos con el ejemplo:
Imaginemos que la tabla a la que queremos acceder tiene estos datos:
Siendo CAMPO1 + CAMPO2 la clave.
Definiremos un cursor del siguiente modo:
WORKING-STORAGE SECTION.
EXEC SQL
DECLARE CURSOR CUR_TABLA FOR
SELECT CAMPO1,
CAMPO2,
CAMPO3,
CAMPO4,
CAMPO5
FROM TABLA1
WHERE CAMPO1 = :CLAVE-CAMPO1
AND CAMPO2 > :CLAVE-CAMPO2
ORDER BY CAMPO1, CAMPO2
END-EXEC
En la linkage recibiremos la información de los campos clave.
LINKAGE SECTION.
01 ENTRADA.
05 ENT-CAMPO1 PIC XX.
05 ENT-CAMPO2 PIC XX.
01 SALIDA.
05 SAL-ULTIMA-CLAVE PIC XXXX.
05 SAL-RECONSULTAR PIC X.
05 SAL-DATOS OCCURS 5 TIMES.
10 SAL-CAMPO1 PIC XX.
10 SAL-CAMPO2 PIC XX.
10 SAL-CAMPO3 PIC XX.
10 SAL-CAMPO4 PIC XX.
10 SAL-CAMPO5 PIC XX.
En el inicio del programa informaremos las variables de acceso al WHERE, realizaremos el OPEN del cursor y un primer FETCH. Podemos poner una validación del campo clave, para comprobar que trae datos, y en caso de no ser así finalizar la ejecución.
INICIO
IF ENT-CAMPO1 EQUAL SPACES OR LOW-VALUES
DISPLAY 'LA CLAVE ESTA VACIA'
PERFORM 90000-FINAL
END-IF
MOVE ENT-CAMPO1 TO CLAVE-CAMPO1
MOVE ENT-CAMPO2 TO CLAVE-CAMPO2
EXEC SQL
OPEN CUR_TABLA
END-EXEC
Controlaremos el SQLCODE. Si no fuese cero, tendríamos que dar un error.
IF SQLCODE NOT EQUAL ZEROES
DISPLAY 'ERROR EN EL OPEN CURSOR. EL SQLCODE ES: 'SQLCODE
PERFORM 90000-FINAL
END-IF
EXEC SQL
FETCH CUR_TABLA
INTO :TABLA1-CAMPO1,
:TABLA1-CAMPO2,
:TABLA1-CAMPO3,
:TABLA1-CAMPO4,
:TABLA1-CAMPO5
END-EXEC
Controlamos el SQLCODE devuelto:
EVALUATE TRUE
WHEN SQLCODE EQUAL ZEROES
DISPLAY 'TODO EN ORDEN'
WHEN SQLCODE EQUAL +100
DISPLAY 'NO ENCUENTRO NADA'
PERFORM 90000-FINAL
WHEN OTHER
DISPLAY 'ALGO VA MAL. EL SQLCODE ES: 'SQLCODE
PERFORM 90000-FINAL
END-EVALUATE
SÓLO si el primer FETCH que realizamos nos devuelve un SQLCODE +100 quiere decir que no hay ningún registro con la clave que hemos introducido.
En posteriores FETCH, un SQLCODE +100 significa que YA NO HAY MÁS registros para esa clave.
En el proceso realizaremos un bucle para ir guardando la información devuelta por el cursor en nuestra tabla SAL-TABLA, e ir haciendo sucesivos FETCH hasta que recupere todos o el máximo de OCCURS de nuestra tabla interna:
PROCESO
PERFORM UNTIL SQLCODE EQUAL +100 OR IND-REGISTROS GREATER 5
PERFORM GUARDAR-EN-SAL-TABLA
PERFORM HAGO-OTRO-FETCH
END-PERFORM
Si salimos del bucle por la condición de SQLCODE = +100 informaremos el campo SAL-RECONSULTAR con una 'N' y el campo SAL-ULTIMA-CLAVE con espacios, pues ya hemos recuperado todos los registros que había en la tabla.
Si salimos del bucle por la condición de IND-REGISTROS > 5 informaremos el campo SAL-RECONSULTAR con una 'S' y el campo SAL-ULTIMA-CLAVE con los campos clave CAMPO1 y CAMPO2.
En cualquiera de los dos casos, cerraremos el cursor:
EXEC SQL
CLOSE CUR_TABLA
END-EXEC
Controlamos el SQLCODE. Si es distinto de cero daremos un error.
IF SQLCODE NOT EQUAL ZEROES
DISPLAY 'ERROR CERRANDO CURSOR. EL SQLCODE ES: 'SQLCODE
END-IF
Según la tabla de nuestro ejemplo, habríamos guardado en SAL-TABLA los registros:
Por lo que nos faltaría por recuperar un último registro. El campo SAL-ULTIMA-CLAVE valdría 'AAFF'.
Para finalizar devolvemos el control al programa llamante.
FINAL
GOBACK.
La siguiente vez que entrásemos al programa accederíamos al cursor con CAMPO1 = 'AA' y CAMPO2 = 'FF' y recuperaríamos el registro que falta:
Os dejo el código completo de un programa de ejemplo para descargar.
Nota: En respuesta a la sugerencia de Jose Antonio, hemos creado un nuevo artículo explicando el uso del ROWSET en los cursores.
12 comentarios:
Sería interesante que ampliaras las explicaciones con el manejo del cursor con las opción 'ROWSET', muy interesante en ocasiones...
Gracias por la idea!
[acento-tejano]
Estamous trabajando en ellou!
[/acento-tejano]
muy buena pagina felicitaciones por estos aportes a todos los que estamos incursionando al mundo del cobol
Gracias por leernos!
tambien seria interesante un ejemplo con un cursor de Lista y Reposicionamiento. Accedientdo por clave a una tabla con 5 campos clave del indice (por ejemplo). Me gustaria ver la estructura.
super buena la página, cmuasg gracias
PERFORM GUARDAR-EN-SAL-TABLA
PERFORM HAGO-OTRO-FETCH
Hola estos perform donde los usas (osea sus instrucciones donde las realizas)
ya que me interesa saber n_n
la liga de descarga no funciona
Bruno, he actualizado el enlace para que puedas ver el código completo del ejemplo.
Un saludo.
usando cursores las puedo meter directo a db2, osea que sea algo sistematizado, donde el usuario no teclee nada
Hola, necesito asesoria, en cuestión de performance y de rendimiento ¿es igual declarar los cursores en WORKING-STORAGE, o en la PROCEDURE DIVISIÓN?
Hola Ernesto.
Efectivamente es igual donde lo declares. Digamos que el estándar es declararlo en la WS, por aquello de que en la PD tienes que tener cuidado de declararlo antes del resto de sentencias :-P
Pero no hay diferencia.