DiazEnriquezAlanDeJesus Investigacion U3
-
Upload
alan-de-jesus-diaz-enriquez -
Category
Documents
-
view
13 -
download
0
description
Transcript of DiazEnriquezAlanDeJesus Investigacion U3
1
INGENIERÍA EN
SISTEMAS COMPUTACIONALES
Materia:
Programación De Base De Datos
Semestre - Grupo - Sistema:
6° Semestre – Semiescolarizado.
Producto Académico:
Investigacion
Tema:
U3.- Programación del lado del servidor
Presenta:
Alan De Jesús Díaz Enriquez, 106Z0085
Docente:
I.S.C. Rafael Zamudio Reyes
H. ALVARADO, VER. AGO. – DIC. 2015
INSTITUTO TECNOLOGICO SUPERIOR
DE ALVARADO
2
INDICE
Introducción ................................................................................................................................................... 3
U3.- Programación del lado del servidor ................................................................................................ 4
3.1.1.- Creación De Vistas ........................................................................................................................... 5
3.1.2. - Creación De Cursores .................................................................................................................. 11
3.1.3. – Creación de funciones ................................................................................................................ 15
3.1.4.- Elementos de un lenguaje de programación (Transact – SQL, PL/SQL, etc.) ................ 19
3.1.5.- Disparadores (Triggers) ................................................................................................................ 22
3.1.6.- Procedimientos almacenados (Stored Procedures) ............................................................. 23
3.2.- Programación del lado del cliente ................................................................................................. 25
Compilación.......................................................................................................................................... 25
Comunicación con el DBMS ............................................................................................................ 26
Correspondencia entre tipos de C y tipos de SQL .................................................................... 27
Impedance Mistmatch ........................................................................................................................ 29
La Captura de Mensajes del DBMS ........................................................................................................ 30
La Estructura SQLCA ......................................................................................................................... 30
La Instrucción WHENEVER .............................................................................................................. 30
3.2.2 JDBC con Java .................................................................................................................................. 31
Conclusión .................................................................................................................................................... 31
Fuentes .......................................................................................................................................................... 32
3
Introducción
La Programación del lado del servidor es una tecnología que consiste en el procesamiento
de una petición de un usuario mediante la interpretación de un script en el servidor web
para generar páginas HTML dinámicamente como respuesta. Todo lo que suceda dentro
del servidor es llamado procesamiento del lado del servidor, o server-side processing.
Cuando tu aplicación necesita interactuar con el servidor (por ejemplo, para cargar o
guardar datos), ésta realiza una petición del lado del cliente (client-side request) desde el
navegador, a través de la red usando invocaciones remotas a métodos (remote procedure
call, RPC). Mientras se está procesando una llamada RPC, tu servidor está ejecutando
código del lado del servidor.
4
U3.- Programación del lado del servidor
Todo lo que suceda dentro del servidor es llamado procesamiento del lado del servidor, o
server-side processing. Cuando tu aplicación necesita interactuar con el servidor (por
ejemplo, para cargar o guardar datos), ésta realiza una petición del lado del cliente (client-
side request) desde el navegador, a través de la red usando invocaciones remotas a
métodos (remote procedure call, RPC). Mientras se está procesando una llamada RPC, tu
servidor está ejecutando código del lado del servidor.
Los primeros servidores web permitían visualizar exclusivamente información estática. Esto
representó bien pronto una limitación; sobre todo desde el momento en el que la actividad
publicitaria y comercial comenzó a concentrarse también en la red Internet.
La unificación de tareas, que inicialmente parecía una ventaja para el desarrollo de páginas
web, se convirtió en realidad en una fuerte limitación para el desarrollo de aplicaciones web.
La programación del lado del servidor es un elemento agregado muy importante en el
diseño o construcción de sitios Web, ya que permite de una u otra forma el manejo de datos
de forma dinámica. Los primeros servidores Web que permitían construir páginas dinámicas
utilizaban CGI. CGI es aún muy común en la actualidad y los servicios de IIS de Microsoft
pueden usar CGI al igual que las páginas ASP. CGI es una tecnología que nos permite
invocar programas compilados o guiones en el servidor Web. CGI se ve a menudo en los
servidores Web de sistemas UNIX, y muchos de los programas CGI son guiones Perl.
5
3.1.1.- Creación De Vistas
Esta sentencia crea una vista nueva o reemplaza una existente si se incluye la cláusula OR
REPLACE. La sentencia_select es una sentencia SELECT que proporciona la definición de
la vista. Puede estar dirigida a tablas de la base o a otras vistas.
Se requiere que posea el permiso CREATE VIEW para la vista, y algún privilegio en cada
columna seleccionada por la sentencia SELECT. Para columnas incluidas en otra parte de
la sentencia SELECT debe poseer el privilegio SELECT. Si está presente la cláusula OR
REPLACE, también deberá tenerse el privilegio DELETE para la vista.
Toda vista pertenece a una base de datos. Por defecto, las vistas se crean en la base de
datos actual. Pera crear una vista en una base de datos específica, indíquela
con base_de_datos.nombre_vista al momento de crearla.
mysql> CREATE VIEW test.v AS SELECT * FROM t;
Las tablas y las vistas comparten el mismo espacio de nombres en la base de datos, por
eso, una base de datos no puede contener una tabla y una vista con el mismo nombre.
Al igual que las tablas, las vistas no pueden tener nombres de columnas duplicados. Por
defecto, los nombres de las columnas devueltos por la sentencia SELECT se usan para las
columnas de la vista. Para dar explícitamente un nombre a las columnas de la vista utilice
la clásula columnaspara indicar una lista de nombres separados con comas. La cantidad
de nombres indicados en columnas debe ser igual a la cantidad de columnas devueltas por
la sentencia SELECT.
Las columnas devueltas por la sentencia SELECT pueden ser simples referencias a
columnas de la tabla, pero tambien pueden ser expresiones conteniendo funciones,
constantes, operadores, etc.
Los nombres de tablas o vistas sin calificar en la sentencia SELECT se interpretan como
pertenecientes a la base de datos actual. Una vista puede hacer referencia a tablas o vistas
en otras bases de datos precediendo el nombre de la tabla o vista con el nombre de la base
de datos apropiada.
Las vistas pueden crearse a partir de varios tipos de sentencias SELECT. Pueden hacer
referencia a tablas o a otras vistas. Pueden usar combinaciones, UNION, y subconsultas.
El SELECT inclusive no necesita hacer referencia a otras tablas. En el siguiente ejemplo se
define una vista que selecciona dos columnas de otra tabla, así como una expresión
calculada a partir de ellas:
6
mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty | price | value |
+------+-------+-------+
| 3 | 50 | 150 |
+------+-------+-------+
La definición de una vista está sujeta a las siguientes limitaciones:
La sentencia SELECT no puede contener una subconsulta en su cláusula FROM.
La sentencia SELECT no puede hacer referencia a variables del sistema o del usuario.
La sentencia SELECT no puede hacer referencia a parámetros de sentencia preparados.
Dentro de una rutina almacenada, la definición no puede hacer referencia a parámetros de
la rutina o a variables locales.
Cualquier tabla o vista referenciada por la definición debe existir. Sin embargo, es posible
que después de crear una vista, se elimine alguna tabla o vista a la que se hace referencia.
Para comprobar la definición de una vista en busca de problemas de este tipo, utilice la
sentencia CHECK TABLE.
La definición no puede hacer referencia a una tabla TEMPORARY, y tampoco se puede
crear una vista TEMPORARY.
Las tablas mencionadas en la definición de la vista deben existir siempre.
No se puede asociar un disparador con una vista.
En la definición de una vista está permitido ORDER BY, pero es ignorado si se seleccionan
columnas de una vista que tiene su propio ORDER BY.
Con respecto a otras opciones o cláusulas incluidas en la definición, las mismas se agregan
a las opciones o cláusulas de cualquier sentencia que haga referencia a la vista creada,
pero el efecto es indefinido. Por ejemplo, si la definición de una vista incluye una cláusula
LIMIT, y se hace una selección desde la vista utilizando una sentencia que tiene su propia
cláusula LIMIT, no está definido cuál se aplicará. El mismo principio se extiende a otras
opciones como ALL, DISTINCT, o SQL_SMALL_RESULT que se ubican a continuación de
la palabra reservada SELECT, y a cláusulas como INTO, FOR UPDATE, LOCK IN SHARE
MODE, y PROCEDURE.
Si se crea una vista y luego se modifica el entorno de proceso de la consulta a traves de la
modificación de variables del sistema, puede afectar los resultados devueltos por la vista:
mysql> CREATE VIEW v AS SELECT CHARSET(CHAR(65)), COLLATION(CHAR(65));
7
Query OK, 0 rows affected (0.00 sec)
mysql> SET NAMES 'latin1';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM v;
+-------------------+---------------------+
| CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
+-------------------+---------------------+
| latin1 | latin1_swedish_ci |
+-------------------+---------------------+
1 row in set (0.00 sec)
mysql> SET NAMES 'utf8';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM v;
+-------------------+---------------------+
| CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
+-------------------+---------------------+
| utf8 | utf8_general_ci |
+-------------------+---------------------+
1 row in set (0.00 sec)
La cláusula opcional ALGORITHM es una extensión de MySQL al SQL estándar.
ALGORITHM puede tomar tres valores: MERGE, TEMPTABLE, o UNDEFINED. El
algoritmo por defecto es UNDEFINED si no se encuentra presente la cláusula ALGORITHM.
El algoritmo afecta la manera en que MySQL procesa la vista.
Para MERGE, el texto de una sentencia que haga referencia a la vista y la definición de la
vista son mezclados de forma que parte de la definición de la vista reemplaza las partes
correspondientes de la consulta.
Para TEMPTABLE, los resultados devueltos por la vista son colocados en una tabla
temporal, la cual es luego utilizada para ejecutar la sentencia.
Para UNDEFINED, MySQL determina el algoritmo que utilizará. En ese caso se prefiere
MERGE por sobre TEMPTABLE si es posible, ya que MERGE por lo general es más
eficiente y porque la vista no puede ser actualizable si se emplea una tabla temporal.
Una razón para elegir explícitamente TEMPTABLE es que los bloqueos en tablas
subyacentes pueden ser liberados despues que la tabla temporal fue creada, y antes de
8
que sea usada para terminar el procesamiento de la sentencia. Esto podría resultar en una
liberación del bloqueo más rápida que en el algoritmo MERGE, de modo que otros clientes
que utilicen la vista no estarán bloqueados mucho tiempo.
El algoritmo de una vista puede ser UNDEFINED en tres situaciones:
No se encuentra presente una cláusula ALGORITHMen la sentencia CREATE VIEW.
La sentencia CREATE VIEW tiene explícitamente una cláusula ALGORITHM =
UNDEFINED.
Se especificó ALGORITHM = MERGE para una vista que solamente puede ser procesada
usando una tabla temporal. En este caso, MySQL emite una advertencia y establece el
algoritmo en UNDEFINED.
Como se dijo anteriormente, MERGE provoca que las partes correspondientes de la
definición de la vista se combinen dentro de la sentencia que hace referencia a la vista. El
siguiente ejemplo muestra brevemente cómo funciona el algoritmo MERGE. El ejemplo
asume que hay una vista v_merge con esta definición:
CREATE ALGORITHM = MERGE VIEW v_merge (vc1, vc2) AS
SELECT c1, c2 FROM t WHERE c3 > 100;
Ejemplo 1: Suponiendo que se utilice esta sentencia:
SELECT * FROM v_merge;
MySQL la gestiona del siguiente modo:
v_merge se convierte en t
* se convierte en vc1, vc2, que corresponden a c1, c2
Se agrega la cláusula WHERE de la vista
La sentencia ejecutada resulta ser:
SELECT c1, c2 FROM t WHERE c3 > 100;
Ejemplo 2: Suponiendo que se utilice esta sentencia:
SELECT * FROM v_merge WHERE vc1 < 100;
Esta sentencia se gestiona en forma similar a la anterior, a excepción de que vc1 < 100 se
convierte en c1 < 100 y la cláusula WHERE de la vista se agrega a la cláusula WHERE de
la sentencia empleando un conector AND (y se agregan paréntesis para asegurarse que
9
las partes de la cláusula se ejecutarán en el orden de precedencia correcto). La sentencia
ejecutada resulta ser:
SELECT c1, c2 FROM t WHERE (c3 > 100) AND (c1 < 100);
Necesariamente, la sentencia a ejecutar tiene una cláusula WHERE con esta forma:
WHERE (WHERE de la sentencia) AND (WHERE de la vista)
El algoritmo MERGE necesita una relación uno-a-uno entre los registros de la vista y los
registros de la tabla subyacente. Si esta relación no se sostiene, debe emplear una tabla
temporal en su lugar. No se tendrá una relación uno-a-uno si la vista contiene cualquiera
de estos elementos:
Funciones agregadas (SUM(), MIN(), MAX(), COUNT(), etcétera)
DISTINCT
GROUP BY
HAVING
UNION o UNION ALL
Hace referencia solamente a valores literales (en tal caso, no hay una tabla subyacente)
Algunas vistas son actualizables. Esto significa que se las puede emplear en sentencias
como UPDATE, DELETE, o INSERT para actualizar el contenido de la tabla subyacente.
Para que una vista sea actualizable, debe haber una relación uno-a-uno entre los registros
de la vista y los registros de la tabla subyacente. Hay otros elementos que impiden que una
vista sea actualizable. Más específicamente, una vista no será actualizable si contiene:
Funciones agregadas (SUM(), MIN(), MAX(), COUNT(), etcétera)
DISTINCT
GROUP BY
HAVING
UNION o UNION ALL
Una subconsulta en la lista de columnas del SELECT
Join
Una vista no actualizable en la cláusula FROM
Una subconsulta en la cláusula WHERE que hace referencia a una tabla en la cláusula
FROM
Hace referencia solamente a valores literales (en tal caso no hay una) tabla subyacenta
para actualizar.
ALGORITHM = TEMPTABLE (utilizar una tabla temporal siempre resulta en una vista no
actualizable)
10
Con respecto a la posibilidad de agregar registros mediante sentencias INSERT, es
necesario que las columnas de la vista actualizable también cumplan los siguientes
requisitos adicionales:
No debe haber nombres duplicados entre las columnas de la vista.
La vista debe contemplar todas las columnas de la tabla en la base de datos que no tengan
indicado un valor por defecto.
Las columnas de la vista deben ser referencias a columnas simples y no columnas
derivadas. Una columna derivada es una que deriva de una expresión. Estos son algunos
ejemplos de columnas derivadas:
3.14159
col1 + 3
UPPER(col2)
col3 / col4
(//subquery//)
No puede insertar registros en una vista conteniendo una combinación de columnas simples
y derivadas, pero puede actualizarla si actualiza únicamente las columnas no derivadas.
Considere esta vista:
CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;
En esta vista no pueden agregarse registros porque col2 es derivada de una expresión.
Pero será actualizable si no intenta actualizar col2. Esta actualización es posible:
UPDATE v SET col1 = 0;
Esta actualización no es posible porque se intenta realizar sobre una columna derivada:
UPDATE v SET col2 = 0;
A veces, es posible que una vista compuesta por múltiples tablas sea actualizable,
asumiendo que es procesada con el algoritmo MERGE. Para que esto funcione, la vista
debe usar inner join (no outer join o UNION). Además, solamente puede actualizarse una
tabla de la definición de la vista, de forma que la cláusula SET debe contener columnas de
sólo una tabla de la vista. Las vistas que utilizan UNION ALL no se pueden actualizar
aunque teóricamente fuese posible hacerlo, debido a que en la implementación se emplean
tablas temporales para procesarlas.
En vistas compuestas por múltiples tablas, INSERT funcionará si se aplica sobre una única
tabla. DELETE no está soportado.
11
La cláusula WITH CHECK OPTION puede utilizarse en una vista actualizable para evitar
inserciones o actualizaciones excepto en los registros en que la cláusula WHERE de
la sentencia_select se evalúe como true.
En la cláusula WITH CHECK OPTION de una vista actualizable, las palabras reservadas
LOCAL y CASCADED determinan el alcance de la verificación cuando la vista está definida
en términos de otras vistas. LOCAL restringe el CHECK OPTION sólo a la vista que está
siendo definida. CASCADED provoca que las vistas subyacentes también sean verificadas.
Si no se indica, el valor por defecto es CASCADED. Considere las siguientes definiciones
de tabla y vistas:
mysql> CREATE TABLE t1 (a INT);
mysql> CREATE VIEW v1 AS SELECT * FROM t1 WHERE a < 2
-> WITH CHECK OPTION;
mysql> CREATE VIEW v2 AS SELECT * FROM v1 WHERE a > 0
-> WITH LOCAL CHECK OPTION;
mysql> CREATE VIEW v3 AS SELECT * FROM v1 WHERE a > 0
-> WITH CASCADED CHECK OPTION;
Las vistas v2 y v3 estan definidas en términos de otra vista, v1. v2 emplea check option
LOCAL, por lo que las inserciones sólo atraviesan la verificación de v2 . v3 emplea check
option CASCADED de modo que las inserciones no solamente atraviesan su propia
verificación sino tambien las de las vistas subyacentes. Las siguientes sentencias
demuestran las diferencias:
ql> INSERT INTO v2 VALUES (2);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO v3 VALUES (2);
ERROR 1369 (HY000): CHECK OPTION failed 'test.v3'
3.1.2. - Creación De Cursores
En bases de datos, el término cursor se refiere a una estructura de control utilizada para el
recorrido (y potencial procesamiento) de los registros del resultado de una consulta.
Un cursor se utiliza para el procesamiento individual de las filas devueltas por el sistema
gestor de base de datos para una consulta. Es necesario debido a que muchos lenguajes
de programación sufren de lo que en inglés se conoce como impedance mismatch. Por
norma general los lenguajes de programación son procedurales y no disponen de ningún
mecanismo para manipular conjuntos de datos en una sola instrucción. Debido a ello, las
filas deben ser procesadas de forma secuencial por la aplicación. Un cursor puede verse
como un iterador sobre la colección de filas que habrá en el set de resultados.
12
Existen sentencias SQL que no requieren del uso de cursores. Ello incluye la
sentencia Insert, así como la mayoría de formas del Update o el Delete. Incluso una
sentencia Select puede no requerir un cursor si se utiliza en la variante de SELECT...INTO,
ya que esta variante sólo devuelve una fila.
Trabajando con cursores
Esta sección introduce la forma en la que los cursores deberían ser utilizados en
aplicaciones con SQL empotrado, según el estándar SQL:2003. No todas las capas de
aplicación para sistemas de bases de datos relacionales siguen este estándar, utilizando
en su lugar una interfaz diferente, como CLI o JDBC.
Un cursor es creado utilizando la sentencia DECLARE CURSOR. Es obligatorio asignarle
un nombre.
DECLARE cursor_name CURSOR FOR SELECT... FROM...
Antes de ser utilizado, el cursor debe ser abierto con una sentencia OPEN . Como resultado
de esta sentencia, el cursor se posiciona antes de la primera fila del set de resultados.
OPEN cursor_name
Un cursor se posiciona en una fila específica del set de resultados con la sentencia FETCH.
Una sentencia fetch transfiere la información de la fila a la aplicación. Una vez todas las
filas han sido procesadas o la sentencia fetch queda posicionada en una fila no existente
(ver cursores de recorrido más abajo), el SGBD devuelve un SQLSTATE '02000'
(acompañado normalmente de un SQLCODE +100) para indicar el final del set de
resultados.
FETCH cursor_name INTO...
El último paso consiste en cerrar el cursor utilizando la sentencia CLOSE .
CLOSE cursor_name
Una vez un cursor está cerrado puede reabrirse de nuevo, lo cual implica que la consulta
es reevaluada y se crea un nuevo set de resultados.
Cursores de recorrido
Los cursores pueden declararse como de recorrido o no. Si son de recorrido, éste indica la
dirección en la que el cursor puede moverse.
13
Un cursor sin recorrido (non-scrollable en inglés) también se conoce como
cursor unidireccional (forward-only en inglés). Cada fila puede ser leída como mucho una
vez, y el cursor automáticamente se mueve a la siguiente fila. Una operación de fetch
después de haber recuperado la última fila posiciona el cursor detrás de la misma y
devuelve SQLSTATE 02000 (SQLCODE +100).
Un cursor de recorrido puede posicionarse en cualquier parte del set de resultados
utilizando la sentencia SQL FETCH. La palabra clave debe ser especificada cuando se
declare el cursor. El valor por defecto es NO SCROLL , aunque algunas capas de aplicación
para bases de datos como JDBC pueden aplicar un valor por defecto diferente.
DECLARE cursor_name sensitivity SCROLL CURSOR FOR SELECT... FROM...
La posición de un cursor de recorrido puede especificarse de forma relativa a la posición
actual del cursor o de forma absoluta a partir del principio del set de resultados.
FETCH [ NEXT | PRIOR | FIRST | LAST ] FROM cursor_name
FETCH ABSOLUTE n FROM cursor_name
FETCH RELATIVE n FROM cursor_name
Los cursores de recorrido pueden potencialmente acceder a la misma fila del set de
resultados múltiples veces. Por lo tanto, modificaciones de datos (insert, update, delete)
realizadas por otras transacciones podrían tener un impacto en el set de resultados. Un
cursor puede ser sensible o insensible a tales modificaciones. Un cursor sensible
recogería las modificaciones que afectarían al set de resultados, mientras que uno
insensible no. Adicionalmente, un cursor puede ser asensible, en cuyo caso el SGBD
intentará, en la medida de lo posible, aplicar los cambios como si fuera sensible.
WITH HOLD
Por norma general los cursores son cerrados automáticamente al final de una transacción,
es decir, cuando se ejecuta un COMMIT o un ROLLBACK, o bien cuando se da un cierre
implícito de la transacción. Este comportamiento puede ser cambiado si el cursor es
declarado utilizando la cláusula WITH HOLD (por defecto cualquier cursor será WITHOUT
HOLD). Un cursor declarado con esta cláusula se mantiene abierto tras un COMMIT y se
cierra después de un ROLLBACK, aunque algunos SGBD se desvían de este
comportamiento estándar y mantienen abierto estos cursores después de un ROLLBACK.
DECLARE cursor_name CURSOR WITH HOLD FOR SELECT... FROM...
Cuando se ejecuta un COMMIT, el cursor WITH HOLD se posiciona antes de la siguiente
fila o registro. Por lo tanto, una operación UPDATE o DELETE posicionada sólo funcionará
después de haber realizado primero un FETCH en la misma transacción.
14
Tomese nota de que JDBC define los cursores como WITH HOLD por defecto. Esto se hace
porque JDBC activa la opción de auto-commit por defecto. Debido a la sobrecarga habitual
relacionada con el auto-commit y los cursores WITH HOLD, ambos deberían estar
explícitamente desactivados en el nivel de conexión.
Sentencias Update/Delete posicionadas
Los cursores no sólo pueden ser utilizados para extraer información de la base de datos a
una aplicación, sino que también sirven para identificar una fila a modificar o borrar en
una tabla. El estándar SQL:2003 define para tal fin las sentencias posicionadas Update y
Delete . Estas sentencias no utilizan una cláusula WHERE normal (con predicados de
condición). En cambio, el cursor identifica la fila, para lo cual debe ser abierto y posicionado
en la misma utilizando la sentencia FETCH .
UPDATE table_name
SET ...
WHERE CURRENT OF cursor_name
DELETE
FROM table_name
WHERE CURRENT OF cursor_name
El cursor debe operar sobre un set de resultados que sea modificable para que una
sentencia posicionada UPDATE o DELETE pueda ejecutarse con éxito. En caso contrario,
el SGBD no sabría como aplicar los cambios en los datos a las tablas subyacentes referidas
en el cursor.
Cursores en transacciones distribuidas
Usar cursores en transacciones distribuidas (entornos X/open XA), que son controladas
utilizando un monitor de transacciones, no es diferente que usar cursores en transacciones
no distribuidas.
Aun así, se debe prestar atención al usar cursores WITH HOLD. Las conexiones pueden
ser usadas por diferentes aplicaciones. Por lo tanto, una vez una transacción ha sido
confirmada y ha terminado, una transacción subsecuente (que fuera de otra aplicación)
podría heredar cursores WITH HOLD ya existentes. Este es un punto que los
programadores de aplicaciones deben tener en cuenta.
15
3.1.3. – Creación de funciones
En este tema se describe cómo crear una función definida por el usuario en SQL Server
mediante Transact-SQL.
En este tema
Antes de empezar:
Limitaciones y restricciones
Seguridad
Para crear una función definida por el usuario:
Crear una función escalar
Crear una función con valores de tabla
Antes de empezar
Limitaciones y restricciones
Las funciones definidas por el usuario no se pueden utilizar para realizar acciones
que modifican el estado de la base de datos.
Las funciones definidas por el usuario no pueden tener una cláusula OUTPUT INTO
que tenga una tabla como destino.
Las funciones definidas por el usuario no pueden devolver varios conjuntos de
resultados.Utilice un procedimiento almacenado si necesita devolver varios
conjuntos de resultados.
El control de errores está restringido en una función definida por el usuario.Una UDF
no admite TRY…CATCH, @ERROR o RAISERROR.
Las funciones definidas por el usuario no pueden llamar a un procedimiento
almacenado, pero pueden llamar a un procedimiento almacenado extendido.
Las funciones definidas por el usuario no pueden utilizar tablas temporales o SQL
dinámicas.Se permiten las variables de tabla.
Las instrucciones SET no se permiten en una función definida por el usuario.
No se admite la cláusula FOR XML
Las funciones definidas por el usuario se pueden anidar; es decir, una función
definida por el usuario puede llamar a otra.El nivel de anidamiento aumenta cuando
se empieza a ejecutar la función llamada y disminuye cuando se termina de ejecutar
la función llamada.Las funciones definidas por el usuario se pueden anidar hasta un
máximo de 32 niveles.Si se superan los niveles máximos de anidamiento, la cadena
completa de funciones de llamada produce un error.Cualquier referencia a código
administrado desde una función Transact-SQL definida por el usuario cuenta como
uno de los 32 niveles de anidamiento.Los métodos invocados desde el código
administrado no cuentan para este límite.
Las siguientes instrucciones de Service Broker no se pueden incluir en la definición
de una función Transact-SQL definida por el usuario:
o EMPEZAR CONVERSACIÓN DE DIÁLOGO
o FINALIZAR CONVERSACIÓN
16
o GET CONVERSATION GROUP
o MOVE CONVERSATION
o RECEIVE
o SEND
Seguridad
Permisos
Se requiere el permiso CREATE FUNCTION en la base de datos y el permiso ALTER en el
esquema en el que se va a crear la función. Si la función específica un tipo definido por el
usuario, requiere el permiso EXECUTE para ese tipo.
Funciones escalares
En el ejemplo siguiente se crea una función escalar de varias instrucciones en la base de
datos AdventureWorks2012.La función toma un valor de entrada, ProductID, y devuelve un
valor de devolución único, la cantidad agregada del producto especificado en el inventario.
IF OBJECT_ID (N'dbo.ufnGetInventoryStock', N'FN') IS NOT NULL
DROP FUNCTION ufnGetInventoryStock;
GO
CREATE FUNCTION dbo.ufnGetInventoryStock(@ProductID int)
RETURNS int
AS
-- Returns the stock level for the product.
BEGIN
DECLARE @ret int;
SELECT @ret = SUM(p.Quantity)
FROM Production.ProductInventory p
WHERE p.ProductID = @ProductID
AND p.LocationID = '6';
IF (@ret IS NULL)
SET @ret = 0;
RETURN @ret;
END;
GO
En el ejemplo siguiente se utiliza la función ufnGetInventoryStock para devolver la cantidad
de inventario actual de aquellos productos que tienen un ProductModelID entre 75 y 80.
SELECT ProductModelID, Name, dbo.ufnGetInventoryStock(ProductID)AS CurrentSupply
FROM Production.Product
WHERE ProductModelID BETWEEN 75 and 80;
17
Funciones con valores de tabla
En el ejemplo siguiente se crea una función insertada con valores de tabla en la base de
datos AdventureWorks2012.La función toma un parámetro de entrada, Id. de cliente
(almacén), y devuelve las columnasProductID, Name, y el agregado de las ventas del año
hasta la fecha como YTD Total para cada producto vendido en el almacén.
IF OBJECT_ID (N'Sales.ufn_SalesByStore', N'IF') IS NOT NULL
DROP FUNCTION Sales.ufn_SalesByStore;
GO
CREATE FUNCTION Sales.ufn_SalesByStore (@storeid int)
RETURNS TABLE
AS
RETURN
(
SELECT P.ProductID, P.Name, SUM(SD.LineTotal) AS 'Total'
FROM Production.Product AS P
JOIN Sales.SalesOrderDetail AS SD ON SD.ProductID = P.ProductID
JOIN Sales.SalesOrderHeader AS SH ON SH.SalesOrderID = SD.SalesOrderID
JOIN Sales.Customer AS C ON SH.CustomerID = C.CustomerID
WHERE C.StoreID = @storeid
GROUP BY P.ProductID, P.Name
);
En el ejemplo siguiente se invoca la función y se especifica el identificador de cliente 602.
SELECT * FROM Sales.ufn_SalesByStore (602);
En el ejemplo siguiente se crea una función con valores de tabla en la base de datos
AdventureWorks2012.La función toma un único parámetro de entrada, EmployeeID, y
devuelve una lista de todos los empleados que dependen directa o indirectamente del
empleado especificado.La función se invoca luego especificando el empleado ID 109.
IF OBJECT_ID (N'dbo.ufn_FindReports', N'TF') IS NOT NULL
DROP FUNCTION dbo.ufn_FindReports;
GO
CREATE FUNCTION dbo.ufn_FindReports (@InEmpID INTEGER)
RETURNS @retFindReports TABLE
(
EmployeeID int primary key NOT NULL,
FirstName nvarchar(255) NOT NULL,
LastName nvarchar(255) NOT NULL,
JobTitle nvarchar(50) NOT NULL,
RecursionLevel int NOT NULL
)
--Returns a result set that lists all the employees who report to the
18
--specific employee directly or indirectly.*/
AS
BEGIN
WITH EMP_cte(EmployeeID, OrganizationNode, FirstName, LastName, JobTitle,
RecursionLevel) -- CTE name and columns
AS (
SELECT e.BusinessEntityID, e.OrganizationNode, p.FirstName, p.LastName,
e.JobTitle, 0 -- Get the initial list of Employees for Manager n
FROM HumanResources.Employee e
INNER JOIN Person.Person p
ON p.BusinessEntityID = e.BusinessEntityID
WHERE e.BusinessEntityID = @InEmpID
UNION ALL
SELECT e.BusinessEntityID, e.OrganizationNode, p.FirstName, p.LastName,
e.JobTitle, RecursionLevel + 1 -- Join recursive member to anchor
FROM HumanResources.Employee e
INNER JOIN EMP_cte
ON e.OrganizationNode.GetAncestor(1) = EMP_cte.OrganizationNode
INNER JOIN Person.Person p
ON p.BusinessEntityID = e.BusinessEntityID
)
-- copy the required columns to the result of the function
INSERT @retFindReports
SELECT EmployeeID, FirstName, LastName, JobTitle, RecursionLevel
FROM EMP_cte
RETURN
END;
GO
-- Example invocation
SELECT EmployeeID, FirstName, LastName, JobTitle, RecursionLevel
FROM dbo.ufn_FindReports(1);
19
3.1.4.- Elementos de un lenguaje de programación (Transact – SQL, PL/SQL, etc.)
Es un lenguaje para la creación de sitios web dinámicos, acrónimo de Java Server Pages.
Está orientado a desarrollar páginas web en Java. JSP es un lenguaje multiplataforma.
JSP fue desarrollado por Sun Microsystems. Comparte ventajas similares a las de
ASP.NET, desarrollado para la creación de aplicaciones web potentes. Posee un motor de
páginas basado en los servlets de Java. Para su funcionamiento se necesita tener instalado
un servidor Tomcat.
Características:
Código separado de la lógica del programa.
Las páginas son compiladas en la primera petición.
Permite separar la parte dinámica de la estática en las páginas web.
Los archivos se encuentran con la extensión (jsp).
El código JSP puede ser incrustado en código HTML.
Los elementos que pueden ser insertados en las páginas JSP son los siguientes: Código:
se puede incrustar código “Java”.
Directivas: permite controlar parámetros del servlet.
Acciones: permite alterar el flujo normal de ejecución de una página.
Ventajas:
Ejecución rápida del servlets.
Crear páginas del lado del servidor.
Multiplataforma.
Código bien estructurado.
Integridad con los módulos de Java.
La parte dinámica está escrita en Java.
Desventajas:
Complejidad de aprendizaje.
PERL
Perl (Practical Extraction and Report Language) es un lenguaje de programación
desarrollado por Larry Wall (lwall at netlabs.com) inspirado en otras herramientas de UNIX
como son: sed, grep, awk, c-shell, para la administración de tareas propias de sistemas
UNIX. No establece ninguna filosofía de programación concreta. No se puede decir que sea
orientado a objetos, modular o estructurado aunque soporta directamente todos estos
paradigmas; su punto fuerte son las labores de procesamiento de textos y archivos.
Lenguaje de programación basado en scripts portable a casi cualquier plataforma. Es muy
utilizado para escribir CGIs. Uno de sus elementos más potentes son las expresiones
20
regulares, que a partir de su versión en Perl han sido adoptadas por otros lenguajes y
plataformas como .NET o Javascript.
Ventajas
Es un buen lenguaje “pegamento”. Se pueden juntar varios programas de una forma
sencilla para alcanzar una meta determinada. Los usuarios de Windows agradecerán
esta propiedad ya que normalmente adolecen de un buen lenguaje tipo “script”.
Es relativamente rápido para un lenguaje tipo “script”.
Está disponible en múltiples plataformas y sistemas operativos (UNIX, Linux y Windows).
Un programa que se escriba teniendo en cuenta la compatibilidad puede ser escrito en
una plataforma y ejecutado en otra.
El desarrollo de aplicaciones es muy rápido.
Hay una colección enorme de módulos que pueden ser incorporados a cualquier “script”
de Perl. Están disponibles en el CPAN (“Comprehensive Perl Archive Network”). En
particular existe una extensión para cálculo numérico denominada PDL.
Perl es gratuito. Mucho más que eso, es “Software Libre”. Esto quiere decir que el código
fuente está disponible para que cualquiera lo pueda ver o modificar, y lo que es más
importante, siempre lo estará. Aunque nunca pretendas cambiar el código, es importante
disponer de la posibilidad de hacerlo, ya que siempre se podrá contratar a una tercera
persona para que lo modifique en el caso de que haya un error, y debería ser posible
solucionarlo.
Le otorga al programador mucha libertad para que haga el programa como quiera. Tal
como dice el eslogan de Perl “Hay más de una forma de hacerlo”.
Desventajas
Es lento para algunas aplicaciones, como programación a bajo nivel, escribiendo un
“driver” para una aplicación o corriendo modelos numéricos de cálculo intensivo. Si bien
se pueden insertar subrutinas FORTRAN o C en Perl, teniendo lo mejor de los dos
mundos, pero con algo más de complejidad.
La libertad que se le otorga al programador puede significar que el resultado sea un
programa ilegible. Si no se escribe con cuidado puede llegar a ser difícil de leer. De hecho
hay un concurso de Perl ofuscado.
Perl es un lenguaje interpretado. Este tema no es tan crítico como suena, los programas
Perl no correrán mucho más rápidos cuando se compilen, la única ventaja está en la
desaparición de la fase inicial de compilación al correr la aplicación.
Utiliza muchos recursos de computó. Esto significa que no es tan ligero como un
programa en C, pero en la práctica es ligero comparado con la potencia de
procesamiento de las computadoras actuales.
21
PHP
PHP es el acrónimo de Hipertext Preprocesor. Es un lenguaje de programación del lado del
servidor gratuito e independiente de plataforma, rápido, con una gran librería de funciones
y mucha documentación. Fue creado originalmente en 1994 por Rasmus Lerdorf, pero
como PHP está desarrollado en política de código abierto, a lo largo de su historia ha tenido
muchas contribuciones de otros desarrolladores.
El cliente solamente recibe una página con el código HTML resultante de la ejecución de la
PHP. Como la página resultante contiene únicamente código HTML, es compatible con
todos los navegadores.
Ventajas:
Muy fácil de aprender.
Se caracteriza por ser un lenguaje muy rápido.
Soporta en cierta medida la orientación a objeto. Clases y herencia.
Es un lenguaje multiplataforma: Linux, Windows, entre otros.
Capacidad de conexión con la mayoría de los manejadores de base de datos: MysSQL,
PostgreSQL, Oracle, MS SQL Server, entre otras.
Capacidad de expandir su potencial utilizando módulos.
Posee documentación en su página oficial la cual incluye descripción y ejemplos de cada
una de sus funciones.
Es libre, por lo que se presenta como una alternativa de fácil acceso para todos.
Incluye gran cantidad de funciones.
No requiere definición de tipos de variables ni manejo detallado del bajo nivel.
Desventajas:
Todo el trabajo lo realiza el servidor y no delega al cliente. Por tanto puede ser más
ineficiente a medida que las solicitudes aumenten de número.
La legibilidad del código puede verse afectada al mezclar sentencias HTML y PHP.
La programación orientada a objetos es aún muy deficiente para aplicaciones grandes.
Dificulta la modularización.
Dificulta la organización por capas de la aplicación.
Seguridad:
PHP es un poderoso lenguaje e intérprete, ya sea incluido como parte de un servidor web
en forma de módulo o ejecutado como un binario CGI separado, es capaz de acceder a
archivos, ejecutar comandos y abrir conexiones de red en el servidor. Estas propiedades
hacen que cualquier cosa que sea ejecutada en un servidor web sea insegura por
naturaleza.
22
PHP está diseñado específicamente para ser un lenguaje más seguro para escribir
programas CGI que Perl o C, y con la selección correcta de opciones de configuración en
tiempos de compilación y ejecución, y siguiendo algunas prácticas correctas de
programación.
3.1.5.- Disparadores (Triggers)
Un disparador define una acción que la base de datos debe llevar a cabo cuando se produce
algún suceso relacionado con la misma. Los disparadores (triggers) pueden utilizarse para
completar la integridad referencial, también para imponer reglas de negocio complejas o
para auditar cambios en los datos. El código contenido en un disparador,
denominado cuerpo del disparador, está formado por bloques PL/SQL. La ejecución de
disparadores es transparente al usuario.
Para crear un disparador (trigger) en una tabla, el usuario con el que accedamos a Oracle
deberá ser propietario de la misma, teniendo así el privilegio ALTER para la tabla ó ALTER
ANY TABLE. Además, dicho usuario, debe disponer del privilegio CREATE TRIGGER.
Existen varios tipos de disparadores, dependiendo del tipo de transacción de disparo y el
nivel en el que se ejecuta el disparador (trigger):
1.- Disparadores de nivel de fila: se ejecutan una vez para cada fila afectada por una
instrucción DML. Los disparadores de nivel de fila se crean utilizando la cláusula for each
row en el comando create trigger.
2.- Disparadores de nivel de instrucción: se ejecutan una vez para cada intrucción DML.
Por ejemplo, si una única intrucción INSERT inserta 500 filas en una tabla un disparador de
nivel de instrucción para dicha tabla sólo se ejecutará una vez. Los disparadores de nivel
de instrucción son el tipo predeterminado que se crea con el comando create trigger.
3.- Disparadores Before y After: puesto que los disparadores son ejecutados por sucesos,
puede establecerse que se produzcan inmediatamente antes (before) o después (after) de
dichos sucesos.
4.- Disparadores Instead Of: puede utilizar INSTEAD OF para indicar a Oracle lo que tiene
que hacer en lugar de realizar las acciones que invoca el disparador. Por ejemplo, podría
usar un disparador INSTEAD OF en una vista para gestionar las inserciones en una tabla
o para actualizar múltiples tablas que son parte de una vista.
5.- Disparadores de esquema: puede crear disparadores sobre operaciones en el nivel de
esquema tales como create table, alter table, drop table, audit, rename, truncate y revoke.
Puede incluso crear disparadores para impedir que los usuarios eliminen sus propias tablas.
En su mayor parte, los disparadores de nivel de esquema proporcionan dos capacidades:
impedir operaciones DDL y proporcionar una seguridad adicional que controle las
operaciones DDL cuando éstar se producen.
23
6.- Disparadores en nivel de base de datos: puede crear disparadores que se activen al
producirse sucesos de la base de datos, incluyendo errores, inicios de sesión, conexiones
y desconexiones. Puede utilizar este tipo de disparador para automatizar el mantenimiento
de la base de datos o las acciones de auditoría.
3.1.6.- Procedimientos almacenados (Stored Procedures)
Un procedimiento almacenado (stored procedure en inglés) es
un programa (o procedimiento) almacenado físicamente en una base de datos. Su
implementación varía de un gestor de bases de datos a otro. La ventaja de un
procedimiento almacenado es que al ser ejecutado, en respuesta a una petición de
usuario, es ejecutado directamente en el motor de bases de datos, el cual usualmente corre
en un servidor separado. Como tal, posee acceso directo a los datos que necesita manipular
y sólo necesita enviar sus resultados de regreso al usuario, deshaciéndose de la sobrecarga
resultante de comunicar grandes cantidades de datos salientes y entrantes.
Usos típicos para procedimientos almacenados incluyen la validación de datos siendo
integrados a la estructura de base de datos (los procedimientos almacenados utilizados
para este propósito a menudo son llamados disparadores; triggers en inglés), o encapsular
un proceso grande y complejo. El último ejemplo generalmente ejecutará más rápido como
un procedimiento almacenado que de haber sido implementado como, por ejemplo, un
programa corriendo en el sistema cliente y comunicándose con la base de datos mediante
el envío de consultas SQL y recibiendo sus resultados.
Los procedimientos pueden ser ventajosos: Cuando una base de datos es manipulada
desde muchos programas externos. Al incluir la lógica de la aplicación en la base de datos
utilizando procedimientos almacenados, la necesidad de embeber la misma lógica en todos
los programas que acceden a los datos es reducida. Esto puede simplificar la creación y,
particularmente, el mantenimiento de los programas involucrados.
Podemos ver un claro ejemplo de estos procedimientos cuando requerimos realizar una
misma operación en un servidor dentro de algunas o todas las bases de datos y a la vez
dentro de todas o algunas de las tablas de las bases de datos del mismo. Para ello podemos
utilizar a los Procedimientos almacenados auto creable que es una forma de generar ciclos
redundantes a través de los procedimientos almacenados.
Implementación
Estos procedimientos, se usan a menudo, pero no siempre, para realizar
consultas SQL sobre los objetos de la base de datos de una manera abstracta, desde el
punto de vista del cliente de la aplicación. Un procedimiento almacenado permite agrupar
en forma exclusiva parte de algo específico que se desee realizar o, mejor dicho, el SQL
apropiado para dicha acción.
Usos
24
Los usos 'típicos' de los procedimientos almacenados se aplican en la validación de
datos, integrados dentro de la estructura del banco de datos. Los procedimientos
almacenados usados con tal propósito se llaman comúnmente disparadores, o triggers.
Otro uso común es la 'encapsulación' de un API para un proceso complejo o grande que
podría requerir la 'ejecución' de varias consultas SQL, tales como la manipulación de un
conjunto de datos enorme para producir un resultado resumido.
También pueden ser usados para el control de gestión de operaciones, y ejecutar
procedimientos almacenados dentro de una transacción de tal manera que las
transacciones sean efectivamente transparentes para ellos.
Ventajas
La ventaja de un procedimiento almacenado, en respuesta a una petición de usuario, está
directamente bajo el control del motor del gestor de bases de datos, que corre generalmente
en un servidor distinto del servidor web, aumentando con ello la rapidez de procesamiento
de las peticiones del usuario. El servidor de la base de datos tiene acceso directo a los
datos necesarios para manipular y sólo necesita enviar el resultado final al usuario. Los
procedimientos almacenados pueden permitir que la lógica del negocio se encuentre como
un API en la base de datos, que pueden simplificar la gestión de datos y reducir la necesidad
de codificar la lógica en el resto de los programas cliente. Esto puede reducir la probabilidad
de que los datos se corrompan por el uso de programas clientes defectuosos o erróneos.
De este modo, el motor de base de datos puede asegurar la integridad de los datos y su
consistencia con la ayuda de procedimientos almacenados. Algunos afirman que las bases
de datos deben ser utilizadas para el almacenamiento de datos solamente, y que la lógica
de negocio sólo debería aplicarse en la capa de negocio de código, a través de aplicaciones
cliente que deban acceder a los datos. Sin embargo, el uso de procedimientos almacenados
no se opone a la utilización de una capa de negocio.
Procedimientos almacenados en MySQL
Desde MySQL 5 los procedimientos almacenados empezaron a ser soportados, como suele
suceder en MySQL las sentencias se ejecutan luego de escribir el signo punto y coma (;),
por esta razón antes de escribir el procedimiento almacenado la función del punto y coma
se asigna a otros caracteres usando la sentencia DELIMITER seguida de un carácter tal
como |, de esta manera el procedimiento puede ser escrito usando los punto y comas sin
que se ejecute mientras se escribe; después de escrito el procedimiento, se escribe
nuevamente la sentencia DELIMITER ; para asignar al punto y coma su función habitual.
El siguiente es un ejemplo de procedimiento almacenado en MySQL:
DELIMITER |
CREATE PROCEDURE autos(IN velocidad int,IN marca varchar(50))
25
BEGIN
IF velocidad < 120 then
INSERT INTO familiares VALUES(velocidad,marca);
ELSE
INSERT INTO deportivos VALUES(velocidad,marca);
END IF;
END;
|
3.2.- Programación del lado del cliente
En esta sección analizaremos algunos de los problemas que se presentan al trabajar con
SQL embebido. Este análisis no pretende ser detallado sino más bien una reseña básica
de los problemas y sus soluciones en el estandard.
Compilación
Al trabajar con SQL embebido en C escribimos un programa con instrucciones en dos
lenguajes distintos: C y SQL. Por lo tanto, será necesario compilar los programas de una
forma diferente cuando trabajamos con SQL embebido en C que cuando trabajamos solo
con C.
Todas las sentencias SQL deberán comenzar con las palabras EXEC SQL y en vez de
ejecutar el compilador de C, ejecutamos el precompilador de SQL embebido. En el RDBMS
PostgreSQL, el precompilador se llama ecpg .
La sintaxis del comando ecpg correspondiente al precompilador es la siguiente:
ecgp [opciones] archivos
Por detalle sobre las opciones consultar la documentacion del comando
Ejemplo compilacion.
Para compilar el archivo prog1.pgc creando un ejecutable con nombre prog1 escribimos la
siguiente secuencia de comandos:
ecpg prog1.pgc
cc -I/usr/local/pgsql/include -c prog1.c
cc -o prog1 prog1.o -L/usr/local/pgsql/lib -lecpg
26
En el primer paso estamos precompilando el código que contiene las sentencias SQL
embebidas en C.
El paso siguiente crea el código objeto (para lo cual necesito los archivos de encabezado
de ECPG que se encuentran en usr/local/pgsql/include
El último paso genera el ejecutable, para lo cual precisa linkear con la biblioteca libecpg
ubicada en /usr/local/pgsql/lib
Ejemplo de código
A continuación presentamos un ejemplo del código C con SQL embebido que corresponde
al programa pepe.ec.
(1) #include <stdio.h>
(2) EXEC SQL include sqlca;
(3) main()
{
(4) EXEC SQL BEGIN DECLARE SECTION;
(5) int cant;
(6) EXEC SQL END DECLARE SECTION;
(7) EXEC SQL connect to 'dbventas';
(8) EXEC SQL
select count(*) into :cant
from cliente;
(9) printf(``La cantidad de tuplas de la tabla Cliente es %d \n'', cant);
}
Comunicación con el DBMS
Comencemos a observar más detenidamente el programa anterior. En particular las líneas
(4) a (6).
Estas instrucciones declaran una variable de comunicación entre el DBMS y el programa.
Siempre que se utilice esa variable en una instrucción SQL se debe escribir ``:'' delante del
nombre de la variable para que el precompilador interprete el símbolo como una variable
de programa. Si se utiliza en cualquier instrucción de C no se debe escribir más que el
nombre de la variable tal cual fue declarado.
27
Podemos utilizar la declaración DECLARE SECTION, para declarar más de una variable.
EXEC SQL BEGIN DECLARE SECTION;
int hostint;
long hostlong;
double hostdbl;
char hostarr[80];
EXEC SQL END DECLARE SECTION;
Finalmente, hacemos notar que se pueden escribir tantas DECLARE SECTION como sean
convenientes.
Correspondencia entre tipos de C y tipos de SQL
Para utilizar correctamente las variables de comunicación, es necesario conocer las
correspondencias entre los tipos de C y los tipos de SQL. Dicha correspondencia es
presentada en tabla siguiente:
SQL Lenguaje C
CHAR(n) char[n + 1]
CHARACTER(n)
SMALLINT short int
INTEGER long int
INT
DECIMAL dec_t o struct decimal
DEC
NUMERIC
SMALLFLOAT float
28
REAL
FLOAT double
DOUBLE PRECISION
MONEY dec_t o struct decimal
SERIAL long int
DATE long int
DATETIME dtime_t o struct dtime
INTERVAL intrvl_t o struct intrvl
La declaración de las variables en los programas tales como pepe.ec arriba, se realiza
según los tipos de C.
Los tipos dec_t, dtime_t e intrvl_t están definidos en diferentes .h que pueden ser incluídos
en nuestros programas mediante la directiva:
EXEC SQL include nomarch
También podemos definir estructuras y tipos del usuarios con typedef. Al utilizar variables
de dichos tipos, podemos hacer trabajar tanto con las componentes como con las
estructuras como un todo. En realidad, siempre que aparece una variable de tipo estructura,
el precompilador expande a la lista de campos correspondientes. Dada la siguiente
declaración:
EXEC SQL struct cliente_t {
int nro_cli;
char nombre[32];
char apellido[32];
} tupla_cli;
La instrucción:
EXEC SQL insert :tupla_cli into cliente;
es equivalente a:
EXEC SQL insert into cliente
values ( :tupla_cli.nro_cli, :tupla_cli.nombre, :tupla_cli.apellido);
29
Por último, cabe notar que Informix las palabras claves ``EXEC SQL'' se pueden substituir
por ``$''.
Impedance Mistmatch
SQL es un lenguaje para manipulación de conjuntos de tuplas, donde cada tupla es similar
a un registro (record o struct) de un lenguaje tradicional.
En general, C maneja datos individuales y no conjuntos. Para manejar conjuntos en C
tenemos que realizar alguna forma de iteración que permita manejar datos individuales.
Debido a la diferencia de granularidad con que trabajan ambos lenguajes, es necesario que
el precompilador provea un mecanismo para resolver este problema. Para ello se introduce
la noción de cursor.
Un cursor es básicamente un puntero a un área de memoria donde está almacenado el
resultado de una consulta. Sin embargo, no es un puntero común del lenguaje de
programación (en nuestro caso de C). Debe manipularse con un conjunto de operaciones
especiales provistas. Algunas de estas operaciones son: Declare, Open, Fetch. A
continuación damos una breve explicación del significado de cada operación.
Declare. Declara un cursor para poder acceder al resultado de una instrucción SQL. Por
ejemplo,
EXEC SQL declare c_tabla cursor for
select *
from tabla;
Open. Ejecuta la consulta asociada al cursor y hace accesible el resultado por medio del
cursor. El cursor queda posicionado antes de la primera tupla del resultado.Por ejemplo,
EXEC SQL open c_tabla;
Fetch. Posiciona el cursor en la siguiente tupla. Luego de un open, es necesario ejecutar
esta operación para poder acceder a la primera tupla. Por ejemplo,
EXEC SQL fetch c_tabla into :struct_tupla_tabla;
while (sqlca.sqlcode == 0) {
print_struct(struct_tupla_tabla);
EXEC SQL fetch c_tabla into :struct_tupla_tabla;
}
La operación fetch permite posicionarse en cualquier tupla del resultado. Esto se logra
agregando alguna de las siguientes opciones antes del nombre del cursor:
Previous. Posiciona el cursor en la tupla anterior a la tupla que está en este momento.
First. Posiciona el cursor en al primer tupla del resultado.
Last. Posiciona el cursor en la última tupla accesible.
Relative n. Posiciona el cursor en la tupla n a partir de su posición actual. Si n es negativo,
entonces estamos especificando una posición anterior a la de la tupla actual.
30
Absolute n. Posiciona el cursor en la tupla de ordinal n del resultado.
La Captura de Mensajes del DBMS
Después de la ejecución de una instrucción SQL, podemos informarnos del estado de la
ejecución o bien por un test explícito utilizando la estructura SQLCA (SQL Communication
Area) o bien por un test implicito utilizando la instrucción WHENEVER. Estas dos formas
de manejo de errores son descriptas brevemente a continuación.
La Estructura SQLCA
En el ejemplo de la operación fetch de la sección 2.4, se utiliza la siguiente instrucción:
while (sqlca.sqlcode == 0)
La variable de estructura llamada sqlca es el mecanismo que se utiliza para recibir
mensajes del DBMS. La estructura se encuentra declarada en el archivo sqlca.h y debe
ser incluída en todos los programas en los que queremos controlar el resultado de la
ejecución de operaciones por parte del DBMS. Un ejemplo de esta inclusión se encuentra
en la línea (2) del programapepe.ec de la sección 2.1.
Si la última operación que se envió ejecutar al DBMS se terminó sin ninguna característica
especial, entonces el valor de la variable sqlca.sqlcode es 0. En caso de que esa ejecución
genere un error, el valor de la variable sqlca.sqlcode será negativo y corresponde a un
código de error. El valor de la variable sqlca.sqlerrm, corresponde a un string que
representa el mensaje de error que emite el DBMS. Cuando el DBMS ejecuta una
instrucción select sobre una tabla que no tiene tuplas o una instrucción fetch que pretende
``pasarse'' de la última tupla, el valor de la variable sqlca.sqlcode es aquel de la
constante SQLNOTFOUND . SQLNOTFOUND es una constante definida en el
archivo sqlca.h que debe ser incluído en caso de utilizar dicha constante.
La variable de estructura sqlca tiene más campos que los presentados aquí. Esos campos
están destinados a recuperar datos tales como el último identificador de tupla generado o
determinar exactamente que ``warning'' fue el que se generó por parte del DBMS. Se
aconseja consultar el manual de SQL embebido provisto con el DBMS en caso de necesitar
estos campos.
La Instrucción WHENEVER
La instrucción whenever funciona como un manejador de excepciones primitivo. En
cualquier parte de nuestro programa podemos utilizar la instrucción whenever.
En lugar de sqlerror, otras declaraciones son posibles tales como not
found o sqlwarning. not found especifica que cuando se ejecuta un select sobre una tabla
sin tuplas o un fetch que pretende referirse a una tupla que está después de la última tupla
del resultado, se continuará la ejecución en la instrucción identificada por la etiqueta.
Con sqlwarning, se continuará la ejecución en la instrucción identificada por la etiqueta
cuando se genere un ``warning''.
31
Una vez que se ejecuta el whenever-goto, éste queda activo hasta que se ejecute
otro whenever-goto con la misma condición o bien se ejecute una
instrucción whenever <condición > continue .
Este mecanismo de manejo de errores tiene sus problemas. Al trabajar con un lenguaje
estructurado, no se puede salir de una función usando un goto. Por ello, es aconsejable
elegir alguna de las siguientes guías:
1. Redefinir la etiqueta de un whenever en cada función que contenga instrucciones
SQL que puedan activarlo.
2. Definir un whenever con su etiqueta correspondiente en cada función que contenga
instrucciones SQL que pueda activar el whenever .
IMPORTANTE !. La primera instrucción en un trozo de instrucciones identificado por una
etiqueta, debe ser un whenever-continue con la misma condición que activó la etiqueta.
De lo contrario, si hay instrucciones SQL en el trozo de instrucciones identificado por la
etiqueta que son capaces de generar las misma condición que nos llevó hasta aquí, el
programa entrará en loop.
3.2.2 JDBC con Java
Java Database Connectivity, más conocida por sus siglas JDBC , es una API que permite
la ejecución de operaciones sobre bases de datos desde el lenguaje de programación Java,
independientemente del sistema operativo donde se ejecute o de la base de datos a la cual
se accede, utilizando el dialecto SQL del modelo de base de datos que se utilice.
El API JDBC se presenta como una colección de interfaces Java y métodos de gestión de
manejadores de conexión hacia cada modelo específico de base de datos. Un manejador
de conexiones hacia un modelo de base de datos en particular es un conjunto de clases
que implementan las interfaces Java y que utilizan los métodos de registro para declarar
los tipos de localizadores a base de datos (URL) que pueden manejar. Para utilizar una
base de datos particular, el usuario ejecuta su programa junto con la biblioteca de conexión
apropiada al modelo de su base de datos, y accede a ella estableciendo una conexión; para
ello provee el localizador a la base de datos y los parámetros de conexión específicos.
A partir de allí puede realizar cualquier tipo de tarea con la base de datos a la que tenga
permiso: consulta, actualización, creación, modificación y borrado de tablas, ejecución
de procedimientos almacenados en la base de datos, etc.
Conclusión
32
Toda base de datos debe tener una serie de características tales como seguridad (sólo
personas autorizadas podrán acceder a la información), integridad (la información se
mantendrá sin pérdidas de datos), e independencia (esta característica es fundamental ya
que una buena base de datos debería ser independiente del sistema operativo o programas
que interactúen con ella). Hay más características que debe reunir una base de datos como
ser consistente (es decir, que la información se guarde sin duplicidades y de manera
correcta). Y finalmente, las bases de datos actuales permiten el manejo correcto de
transacciones. Esto significa que se ha de permitir efectuar varias operaciones sobre la
base de datos pero tratadas a modo de una sola. Es decir, si en el conjunto de las
operaciones de una transacción se produce un error, entonces se deshacen todas las
operaciones realizadas anteriormente y se cancela la transacción.
Fuentes
33
Vistas Con Base De Datos
https://yoalo.wikispaces.com/2.1.4+Creacion+Vistas+Base+de+Datos+viewElProcesoUnifi
cadodeSoftware.RogerPressman.
Creación de funciones
https://msdn.microsoft.com/es-es/library/ms191320(v=sql.120).aspx
Procedimientos Almacenados
https://es.wikipedia.org/wiki/Procedimiento_almacenado
JDBC
http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro21/432_conectores_de_base_de
_datos_para_java_jdbc.html