V.PROVEEDOR FROM V WHERE V.CIUDAD = :Y ORDER BY V# ASC ; /* define el , V.STATUS cursor */ EXEC SQ L OPEN X ; DO para todas las EXEC SQL FETCH filas X INTO /* ejecuta la de V accesibles :V#, ¡PROVEEDOR /* recupera a consulta nediante X ; :STATUS ; el siguiente proveedor */ */ EXEC SQ L END ; CLOSE X ; / * desactiva el cursor X */
Figura 4.4 Ejemplo de recuperación de múltiples filas.
evalúa en este punto, DECLARE CURSOR es una expresión meramente declarativa. La expre- sión es producida al abrir el cursor ("OPEN X"). Entonces se usa la instrucción "FETCH X INTO ..." para recuperar (una a una) las filas del conjunto resultante asignando a las variables anfitrión los valores recuperados de acuerdo con las especificaciones de la cláusula INTO de esa instrucción. (Para efectos de simplicidad dimos a las variables anfitrión los mismos nombres de las columnas correspondientes de la base de datos. Observe que el SELECT en la declaración del cursor no tiene ninguna cláusula INTO propia.) Debido a que habrá muchas filas en el con- junto resultante, el FETCH aparecerá normalmente dentro de un ciclo; el ciclo se repetirá en tanto queden filas en ese conjunto. Al salir del ciclo, el cursor X se cierra ("CLOSE X").
Ahora consideraremos con más detalle los cursores y las operaciones con cursores. En primer lugar, un cursor se declara por medio de una instrucción DECLARE CURSOR, la cual tiene la siguiente forma general
EXEC SQL DECLARE <nombre de cursor> CURSOR
FOR <expresión de tabla> [ <ordenamiento> ] ;
(para ser breves, ignoramos algunas especificaciones opcionales). Para una explicación completa de <expresión de tabla >, consulte el apéndice A. El <ordenamiento> opcional toma la form
ORDER BY <lista de elementos a ordenar separados con comas>
donde (a) la lista separada con comas de <elemento a ordenar> no debe estar vacía —vea el párra- fo inmediato siguiente— y (b) cada <elemento a ordenar> individual consiste en un nombre de columna {no calificado, cabe señalar), seguido de manera opcional por ASC (ascendente) o DESC (descendente), con ASC como el valor predeterminado.
Nota: Definimos el término lista con comas como sigue. Sea <xyz> un elemento para
notar una categoría sintáctica arbitraria (es decir, todo lo que aparezca a la izquierda de una regla de producción BNF). Entonces la expresión < lista de xyz separadas con comas> denota una cuencia de cero o más elementos <xyz> en la cual cada par de <xyz> adyacentes está separado por una coma (y tal vez por uno o más espacios). Observe que haremos un uso amplio de esta notación en las reglas de sintaxis futuras (en todas las reglas, no sólo en las de SQL).
Como mencioné antes, la instrucción DECLARE CURSOR es declarativa, no ejecutable; declara un cursor con el nombre especificado y con la expresión de tabla y ordenamiento
pecificados en asociación permanente con él. La expresión de tabla puede incluir referencias a variables anfitrión. Un programa puede tener cualquier cantidad de instrucciones DECLARE CURSOR, cada una de las cuales debe ser (por supuesto) para un cursor diferente.
Para operar sobre los cursores se ofrecen las instrucciones ejecutables: OPEN, FETCH y
CLOSE.
■ La instrucción
EXEC SQL OPEN <nombre de cursor> ;
abre o activa el cursor especificado (que no debe estar abierto actualmente). En efecto, la expresión de tabla asociada con el cursor es evaluada (empleando los valores ac- tuales para cualquier variable anfitrión referida dentro de esa expresión); entonces se identifica un conjunto de filas y se convierte en el conjunto activo del cursor. El cur- sor también identifica una posición dentro de ese conjunto activo que es la posición in- mediata anterior a la primera fila. (Para que el concepto de posición tenga sentido, se considera que los conjuntos activos siempre tienen un orden.* El orden puede ser el definido por la cláusula ORDER BY o bien por un ordenamiento determinado por el sis- tema en ausencia de dicha cláusula).
■ La instrucción
EXEC SQL FETCH <nombre de cursor>
INTO <lista de referencias a variable anfitrión separadas con comas> ;
avanza el cursor especificado (que debe estar abierto) hacia la siguiente fila del con- junto activo y luego asigna el iésimo valor de esa fila a la iésima variable anfitrión referida en la cláusula INTO. Si no hay una siguiente fila al ejecutar FETCH, se asigna el valor 02000 a SQLSTATE y no se recuperan datos.
■ La instrucción
EXEC SQL CLOSE <nombre de cursor> ;
cierra o desactiva el cursor especificado (que debe estar abierto actualmente). Ahora el cur- sor no tiene ningún conjunto activo. Sin embargo, puede volverse a abrir después, en cuyo caso adquirirá otro conjunto activo; probablemente no el mismo que antes, en especial si en el transcurso cambió el valor de cualquiera de las variables anfitrión referidas en la de- claración del cursor. Observe que modificar el valor de dichas variables mientras el cur- sor está abierto no tiene ningún efecto en el conjunto activo actual.
Otras dos instrucciones pueden incluir referencias a cursores; a saber, las formas CURRENT de UPDATE y DELETE. Si un cursor, digamos X, está ubicado actualmente en una fila en par-
* Por supuesto, los conjuntos por sí mismos no tienen un orden (vea el capítulo 5), de modo que un "con- junto activo" en realidad no es un conjunto como tal. Sería mejor considerarlo como una lista ordenada o
96 Parte I / Preliminares
ticular, entonces es posible modificar (UPDATE) o eliminar (DELETE) "la fila actual (CURRENT) de X"; es decir, la fila en la que está posicionado X. Por ejemplo:
EXEC SQL UPDATE V
SET STATUS • STATUS + :AUMENTO WHERE CURRENT OF X ;
Nota: Las formas CURRENT de UPDATE y DELETE no están permitidas cuando la ex-
presión de tabla en la declaración del cursor define una vista no actualizable como parte de una instrucción CREATE VIEW (vea el capítulo 9, sección 9.6).