UNIVERSIDAD DE CASTILLA-LA MANCHA ESCUELA SUPERIOR DE INFORMÁTICA SQL EMBEBIDO FELIPE GARCÍA GÓMEZ Profesor: D. Francisco Ruiz González Asignatura: Bases de Datos Titulación: Ing. Sup. Informática Fecha: 14-Marzo-2001 SQL EMBEBIDO 1. INTRODUCCIÓN 2. ESTRUCTURA DE UN PROGRAMA 3. ELEMENTOS DE UN PROGRAMA CON SQL EMBEBIDO 3.1 DELIMITADORES 3.2 ÁREA DE COMUNICACIÓN 3.3 VARIABLES DEL PROGRAMA 4. INTRODUCCIÓN DE MANIPULACIÓN SIN CURSORES 5. INTRODUCCIÓN DE MANIPULACIÓN CON CURSORES 6. EJEMPLO 7. COMPILACIÓN 8. BIBLIOGRAFÍA UCLM-ESI . Bases de Datos 1 SQL EMBEBIDO 1.INTRODUCCIÓN El acceso a una base de datos relacional desde un programa se nos puede plantear necesario cuando se piensa en el desarrollo de aplicaciones complejas que se necesitan: manipulación individualizada de las tuplas, estructuras de programación tradicionales (selección y repetición), interacción con el usuario y gestión de errores. Por ello, la propuesta estándar del lenguaje SQL/92 proporciona distintas interfaces del lenguaje, es decir una sintaxis para poder usar el SQL en distintos contextos. Estas interfaces son: el SQL directo (o interactivo) y el SQL embebido. El SQL embebido está pensado para ser utilizado intercalando sus instrucciones en el código de un programa escrito en un lenguaje de programación al que se denomina lenguaje huésped (FORTRAN, COBOL, C, etc.). Estas instrucciones se ejecutan cuando se ejecuta el programa de acuerdo a su lógica interna. En este contexto, el intercambio de información con el SGBD se realiza a través de variables del lenguaje, a las que se denomina variables huéspedes; por ejemplo, el resultado de las consultas es asignado a variables del programa declaradas con ese fin. Por tanto, la idea básica del trabajo con SQL embebido en lenguajes tradicionales es escribir un programa que manipule la base de datos con SQL usando las estructuras de control y variables del lenguaje tradicional. La dificultad principal que se plantea en el acceso a una base de datos relacional desde un programa reside en la incompatibilidad entre los tipos de estructuras del modelo de datos y del lenguaje de programación. Para superar esta dificultad existen dos opciones: - Restringir las consultas a aquellas que devuelvan una única tupla o - Introducir algún mecanismo que permita seleccionar y manipular las tuplas de una relación individualmente, este último mecanismo viene representado por los cursores. En esencia un cursor es un puntero destinado a apuntar a las tuplas de una relación. El cursor puede moverse a través de las tuplas de la relación, pudiéndose en cualquier momento seleccionar o actualizar la tupla apuntada. 2.ESTRUCTURA DE UN PROGRAMA CON SQL EMBEBIDO La estructura típica de un programa de manipulación de base de datos es la siguiente: Programa … Declaración de variables … Declaración de variables huéspedes para acceso a la base de datos Programa…… Fin declaración de variables huéspedes para acceso a la base de datos Declaración de variables … … Fin declaración variables Declaración de de variables huéspedes para acceso a la base de datos Comienzo del código del programa … … Fin declaración de variables huéspedes para acceso a la base de datos … instrucciones propias del lenguaje … Fin declaración de variables Conexión a la base de datos Comienzo del código del programa … … instruccionespropias de SQLdel lenguaje instrucciones ... … Desconexión de lade base de datos Conexión a la base datos … … instruccionesdepropias instrucciones SQL del lenguaje … ... Fin del código de programa 3.ELEMENTOS DE UN PROGRAMA CON SQL EMBEBIDO UCLM-ESI . Bases de Datos 2 SQL EMBEBIDO Ya hemos comentado que la inclusión de sentencias SQL dentro de un programa requiere que se dote a éste de algunos nuevos elementos de programación. Éstos permiten que existan dentro del programa sentencias escritas en un lenguaje (SQL) ajeno al de programación y soportan la comunicación de peticiones y resultados entre el programa y el SGBD. Son , entre otros, los siguientes: - Delimitadores Son partículas añadidas a la sintaxis de las sentencias SQL para distinguirlas dentro del programa fuente. - Área de Comunicación Es un área de datos definida en el programa que es utilizada por el SGBD para comunicarle a aquél si su última petición se ha ejecutado correctamente o no. - Variables de Programa Sirven principalmente para contener en ellas los valores de datos que el programa lee o escribe en las columnas de las tablas. 3.1 DELIMITADORES Los compiladores de un lenguaje no entienden las sentencias SQL como instrucciones propias del mismo. Por ello, deben aquellas incluirse entre delimitadores que sirven para distinguirlas dentro del texto del programa fuente y permiten que sean procesadas por el Precompilador. Todas las instrucciones del SQL embebido van precedidas de las palabras reservadas EXEC SQL, de forma que son fácilmente identificables por el precompilador, y finalizan con un símbolo especial. En el lenguaje C este símbolo es el punto y coma (;). 3.2 ÁREA DE COMUNICACIÓN DE SQL Cuando se ejecuta un programa que tiene sentencias SQL embebidas, éstas son ejecutadas por el SGBD y luego éste devuelve al programa los datos pedidos, si existen. Además, debe devolver una información que indique al programa si su petición se ha ejecutado correctamente o no. Para ello, se usa un área definida dentro del programa que se llama Área de Comunicación de SQL (en inglés SQLCA: SQL Communication Area). La SQLCA consiste en un conjunto de variables que almacenan información sobre el estado (y los errores, si se producen) de la última instrucción que el programa ejecutó sobre la base de datos. Para poder hacer uso de estas variables hay que declararla de la siguiente manera: EXEC SQL INCLUDE SQLCA; En un programa, cualquier instrucción SQL debería estar seguida por código que controlase los valores de las variables SQLCODE y SQLSTATE relativos a la ejecución de la instrucción; para simplificar esta tarea el lenguaje proporciona una sentencia para el control general de errores, ésta es la sentencia WHENEVER: EXEC SQL WHENEVER condición acción condición ::= {SQLERROR | NOT FOUND} acción ::={CONTINUE | GO TO etiqueta} - NOT FOUND se evalúa a cierto si no se han encontrado datos que cumplan las condiciones especificadas en la instrucción (SQLCODE =+100). - SQLERROR se evalúa a cierto si ha ocurrido algún error en la ejecución de la instrucción (SQLCODE < 0). La sentencia WHENEVER no es una instrucción ejecutable, es más bien una directriz al procesador del lenguaje SQL: - WHENEVER condición GO TO etiqueta significa que el procesador de SQL incluirá detrás de cualquier sentencia SQL del programa la sentencia IF condición THEN GO TO etiqueta - WHENEVER condición CONTINUE significa que el procesador de SQL no tomará ninguna acción siendo responsabilidad del programador controlar el flujo del programa. UCLM-ESI . Bases de Datos 3 SQL EMBEBIDO 3.3 VARIABLES DEL PROGRAMA Las variables del lenguaje que son utilizadas en instrucciones SQL (variables huéspedes) deben ser declaradas en una sección especial encabezada y terminada de la siguiente forma: EXEC SQL BEGIN DECLARE SECTION; ... declaración de tipos y variables en C EXEC SQL END DECLARE SECTION; Ejemplo: EXEC SQL BEGIN SECTION; char cd[6]; int aux; char cpx[4]; char cpy[4]; EXEC SQL END DECLARE SECTION; Las variables deben tener un tipo apropiado al uso que se va a hacer de ellas (la compatibilidad de tipos entre el lenguaje de programación y el SGBD depende de cada sistema particular); sintácticamente pueden aparecer en una instrucción SQL en cualquier lugar en el que puede aparecer un literal y deben ir precedidas del símbolo dos puntos ( : ). De las instrucciones SQL que se pueden utilizar, es interesante destacar dos de ellas: la conexión a la base de datos y la desconexión. Estas instrucciones tienen la siguiente sintaxis: EXEC SQL CONNECT 'base_datos'; EXEC SQL DISCONNECT; Es necesario matizar que antes de efectuar cualquier operación sobre la base de datos es necesario conectarse a la misma usando la primera instrucción. Asimismo, para un correcto funcionamiento de las sesiones de base de datos en el servidor, es obligatorio desconectarse de la base de datos antes de que el programa finalice. 4. INTRODUCCIÓN DE MANIPULACIÓN SIN CURSORES Hay una necesidad de cursores debido a que: - SQL interactivo maneja conjuntos en lugar de registros aislados. - El lenguaje de programación maneja un registro a la vez. - El cursor es el mecanismo que permite moverse en un conjunto de tuplas para ser manipuladas de una en una. Sin embargo, existen una serie de operaciones que no involucran cursores, éstos son: - Select: Permite asignar a un conjunto de variables el contenido de una tupla resultante de una operación - Insert - Update - Delete La estructura de SELECT es: SELECT [ALL | DISTINCT] lista_elemento_ selección INTO lista_variable FROM lista_relación [WHERE condición_búsqueda] [GROUP BY lista_atributo] [HAVING condición_búsqueda] UCLM-ESI . Bases de Datos 4 SQL EMBEBIDO Ejemplo: “Obtener el código del departamento al que pertenece el profesor de código ‘JRF’ ”. EXEC SQL SELECT cod_departamento INTO :vector FROM Profesor WHERE cod_pro = ‘JRF’; Aquí la variable vector recibirá el valor de la columna de la tabla Profesor que cumpla la condición (como máximo una fila). En este contexto, la sentencia SELECT debe devolver una única tupla, en caso contrario se producirá un error. Como se puede observar la única variante de la sentencia consiste en la cláusula INTO que especifica la lista de variables del programa que serán utilizadas para recibir los datos seleccionados. Las sentencias de actualización: UPDATE (Permite modificar una o más tuplas de una tabla), INSERT (Permite agregar una tupla a una tabla) y DELETE (Permite eliminar una o más tuplas), tienen la misma sintaxis que en el SQL interactivo con la única diferencia de que pueden incluir variables huéspedes. Ejemplo de actualización: “Transferir la docencia de un profesor cuyo código se lee en la variable cpx a un profesor cuyo código se lee en la variable cpy (cpx y cpy declaradas en un ejemplo anterior)”. EXEC SQL UPDATE Docencia SET cod_pro = :cdy WHERE cod_pro = :cdx Ejemplo: Implementado en C con SQL embebido #include <stdio.h> EXEC SQL include sqlca; main() { EXEC SQL BEGIN DECLARE SECTION; int cant; EXEC SQL END DECLARE SECTION; EXEC SQL connect to 'dbventas'; EXEC SQL select count(*) into :cant from cliente; printf(``La cantidad de tuplas de la tabla Cliente es %d \n'', cant); } 5. INTRODUCCIÓN DE MANIPULACIÓN CON CURSORES Como se ha comentado anteriormente, un cursor es un objeto SQL que permite la manipulación de las tuplas de una relación de forma individualizada; intuitivamente se puede ver como un puntero a las tuplas de una relación. Un cursor siempre va asociado a una relación que se especifica al ser declarado. Ya que el objetivo de su uso es poder navegar a través de las tuplas que constituyen dicha relación para posteriormente manipularlas, estas tuplas deben estar ordenadas, siendo este orden implícitamente definido por el sistema o bien definido por el programador en la declaración del cursor. Desde que el cursor es activado (apertura del cursor) siempre tiene una posición (posición actual) dentro del conjunto ordenado de tuplas. Esta posición puede ser: delante de una tupla, en una tupla, y detrás de una tupla. Esta posición actual va a ser relevante para las instrucciones de manipulación de la base de datos basadas en el uso de cursores. A continuación se presentan cada una de ellas. UCLM-ESI . Bases de Datos 5 SQL EMBEBIDO Definición del cursor DECLARE cursor CURSOR FOR cursor_especificación cursor_especificación ::= expresión_de_relación [ORDER BY lista_elemento_orden] [FOR {READ ONLY | UPDATE [OF lista_nom_atributo]] elemento_orden ::= {nom_atributo | entero_positivo} [ASC | DESC] La expresión_de_relación define la relación asociada al cursor, que será una sentencia SELECT; su sintaxis es la misma que la del SQL interactivo con la diferencia de que puede incluir variables huéspedes. La cláusula ORDER BY permite especificar un orden para las tuplas de la relación definida por expresión_de_relación. Los nombres de atributo o los enteros positivos (ordinal de la posición de un atributo) se refieren a atributos de la relación definida por expresión_de_relación; los enteros positivos se utilizan cuando el correspondiente atributo de la relación no lleva un nombre, es decir es un dato calculado. Si no se incluye la cláusula ORDER BY, el sistema establece un orden por defecto. La cláusula FOR READ ONLY (o UPDATE [OF lista_nom_atributo] ) indica que la relación asociada al cursor no puede (o puede) ser actualizada por medio de las instrucciones UPDATE y DELETE. Apertura del cursor OPEN cursor La apertura de un cursor en un programa significa la evaluación de la expresión_de_relación asociada. Cuando un cursor se abre, su posición actual pasa a ser delante de la primera tupla. Manejo del cursor y selección de tuplas FETCH [[selector_de_tupla] FROM] cursor INTO lista_variables La instrucción FETCH permite mover el cursor dentro del conjunto ordenado de tuplas y seleccionar (leer) la tupla en la que queda colocado; su posición actual después de ejecutarse la instrucción es en la tupla seleccionada . El selector_de_tupla puede ser: next, prior, first, last, absolute n, relative n. Para los casos next, prior y relative el movimiento es relativo a la posición actual del cursor antes de ejecutarse la instrucción fetch. En las opciones absolute n y relative n, un número positivo (respectivamente, negativo) indica movimiento hacia delante (respectivamente, detrás) según la secuencia de ordenación de las tuplas. La lista de variables debe contener una variable huésped por cada atributo de la relación asociada al cursor, estas variables recibirán los valores de la tupla seleccionada. Si la instrucción FETCH no selecciona ninguna tupla, es decir no existe la tupla siguiente (next) o la tupla anterior (prior) a la tupla en la posición actual del cursor, o bien no existe la enésima tupla a partir de la posición actual (absolute y relative) hacia delante (n positivo) o hacia detrás (n negativo), entonces la posición actual del cursor después de ejecutarse la instrucción pasa a ser detrás de la última tupla o delante de la primera tupla. UCLM-ESI . Bases de Datos 6 SQL EMBEBIDO Borrado de tuplas con cursor DELETE FROM relación WHERE CURRENT OF cursor Esta instrucción permite borrar la tupla en la posición actual del cursor, relación es la relación que va a ser actualizada (el cursor cursor debe estar asociado a ella). Después de ejecutarse la instrucción, la posición actual del cursor pasa a ser delante de la tupla siguiente a la tupla que ha sido borrada o detrás de la última tupla si es que la tupla borrada era la última de la relación. Actualización de tuplas con cursor UPDATE relación SET lista_asignación WHERE CURRENT OF cursor Esta instrucción permite actualizar la tupla en la posición actual del cursor. En lista_asignación se indican las actualizaciones que se van a aplicar a los atributos de la tupla apuntada. La sintaxis de esta cláusula es similar a la del SQL interactivo con la excepción de que se pueden incluir referencias a variables huéspedes. La ejecución de esta instrucción no modifica la posición actual del cursor. 7. EJEMPLO */ - Este ejemplo de programa en C (usando SQL embebido) imprimirá un informe. - Este programa deberá ser precompilado para las sentencias SQL, antes de la compilación normal. */ /* ******************************************************/ /* ESTE PROGRAMA NO ES COMPILABLE O EJECUTABLE */ /* SU PROPOSITO ES SÓLO DE SEVIR DE EJEMPLO */ /*******************************************************/ #include <stdio.h> /* Esta sección declara las variables locales */ EXEC SQL BEGIN DECLARE SECTION; int ID_comprador; char Nombre[100], Apellidos[100], Producto[100]; EXEC SQL END DECLARE SECTION; /* Esto incluye la variable SQLCA */ EXEC SQL INCLUDE SQLCA; main() { /* Este es un posible camino para conectarse con la base de datos */ EXEC SQL CONNECT UserID/Password; UCLM-ESI . Bases de Datos 7 SQL EMBEBIDO /* Este código informa si estás conectado a la base de datos o si ha habido algún error durante la conexión*/ if(sqlca.sqlcode) { printf(Printer, "Error conectando al servidor de la base de datos.\n"); exit(); } printf("Conectado al servidor de la base de datos.\n"); /* Esto declara un "Cursor". Éste es usado cuando una consulta devuelve más de una fila, y una operación va a ser realizada en cada fila resultante de la consulta. Después "Fetch" será usado para sacar cada fila, una a una, pero para la consulta que está actualmente ejecutada, se usará el estamento "Open". El "Declare" simplemente establece la consulta.*/ EXEC SQL DECLARE ProductoCursor CURSOR FOR SELECT PRODUCTO, ID_COMPRADOR FROM ANTIGÜEDADES ORDER BY PRODUCTO; EXEC SQL OPEN ProductoCursor; /* Fetch pone los valores de la "siguiente" fila de la consulta en las variables locales, respectivamente.*/ EXEC SQL FETCH ProductoCursor INTO :Producto, :ID_comprador; while(!sqlca.sqlcode) { /* Con cada fila, además hacemos un par de cosas. Primero, aumentamos el precio $5 (honorarios por tramitaciones) y extraemos el nombre del comprador. Para hacer esto, usaremos Update y Select, antes de imprimir la línea en la pantalla. La actuaclización, sin embargo, asume que un comprador dado sólo ha comprado uno de todos los productos dados, o sino, el precio será incrementado demasiadas veces. Además observa los dos puntos antes de los nombres de las variables locales cuando son usada dentro de sentencias de SQL.*/ EXEC SQL UPDATE ANTIGÜEDADES SET PRECIO = PRECIO + 5 WHERE PRODUCTO = :Producto AND ID_COMPRADOR = :ID_comprador; EXEC SQL SELECT NOMBREPROPIETARIO, APELLIDOPROPIETARIO INTO :Nombre, :Apellidos FROM PROPIETARIOS_ANTIGÜEDADES WHERE ID_COMPRADOR = :ID_comprador; printf("%25s %25s %25s", Nombre, Apellidos, Producto); EXEC SQL FETCH ProductoCursor INTO :Producto, :ID_comprador; } /* Cierra el cursor */ EXEC SQL CLOSE ProductoCursor; EXEC SQL DISCONNECT; exit(); } 8. COMPILACIÓN Para compilar un programa SQL embebido en C podemos utilizar un precompilador denominado esql . El archivo debe tener extensión .ec, así para compilar por ejemplo un archivo llamado miprograma.ec creando un ejecutable con nombre miprograma escribimos el siguiente comando: esql –o miprograma miprograma.ec UCLM-ESI . Bases de Datos 8 SQL EMBEBIDO 9. BIBLIOGRAFÍA -Benavides Abajo,J; Olaizola Bartolomé,J.M.;Rivero Cornelio,E. SQL Para usuarios y programadores(Segunda Edición). Ed. Paraninfo 1992. -http://www.infor.una.es/~chernan/sqlemb.html -http://mural.uv.es/gerloal/cap5.htm -http://www2.ing.puc.cl/~jnavon/11C2412/Clases.html UCLM-ESI . Bases de Datos 9