Introducción a SQL TEMA 5: MODIFICACIÓN DE LA BASE DE DATOS EN SQL 5.6 SUBCONSULTAS ANIDADAS SQl proporciona un mecanismo para las sub consultas anidadas. Una sub consulta es una expresión SQL de la forma select-from-where que está dentro de otra consulta SQL. Un uso común de esta sub consultas es posibilitar al SQL el poder decidir si una determinada salida se encuentra ó no en un conjunto de valores generados por esta sub consulta, poder comparar una salida con un conjunto de valores ó comparar la cardinalidad de dos conjuntos de datos. 5.6.1 Pertenencia de Conjuntos En este caso con la cláusula conectiva in se comprueba la pertenencia a un conjunto donde este conjunto es generado por la sub consulta, al contrario si se desea generar filas en que el resultado de una condición no se encuentra en un conjunto generado por la sub consulta se utiliza la cláusula not in. La conectiva in comprueba la pertenencia a un conjunto, donde el conjunto es la colección de valores resultado de una cláusula select. Ejemplo: “Encontrar todos los clientes que tienen tanto un préstamo como una cuenta en el banco” ♦ Solución: select distinct id_cliente from Prestatario where id_cliente in (select id_cliente from Impositor) Este ejemplo, muestra que es posible escribir la misma consulta de diferentes formas en SQL. Esta flexibilidad es de gran importancia puesto que permite al usuario pensar en una consulta del modo que le parezca más natural. También se puede comprobar la pertenencia a un conjunto en una relación cualquiera. Ejemplo: “Listar los clientes que tienen tanto una cuenta como un préstamo en la sucursal Subtiava”. ♦ Solución: select distinct id_cliente from Prestatario, Prestamo where Prestatario.numero_prestamo = Prestamo.numero_prestamo and Prestamo.nombre_sucursal = ’Subtiava’ and (Cuenta.nombre_sucursal, id_cliente) in (select nombre_sucursal, id_cliente from Impositor, Cuenta where Impositor.numero_cuenta = Cuenta.numero_cuenta) En este caso la consulta involucra directamente a dos relaciones ó tablas Impositor (clientes con cuentas) y Prestatario (clientes con préstamos), es posible acceder al Nombre de la 1 Introducción a SQL Sucursal desde Prestatario y desde Impositor por medio de las relaciones Prestamo y Cuenta respectivamente. ♦ Conectiva not in Ejemplo: “Encontrar todos los clientes que tienen un préstamo en el banco pero no tienen una cuenta”. ♦ Solución: select distinct id_cliente Prestatario where id_cliente not in (select id_cliente from Impositor) Los operadores in y not in también se pueden utilizar sobre conjuntos enumerados. Ejemplo: “Seleccionar todos los nombres de los clientes que tienen un préstamo en el banco y cuyos nombres no son ni “Pedro” ni “Héctor”. ♦ Solución: select distinct id_cliente from Prestatario where id_cliente not in (‘Pedro’, ‘Héctor’) 5.6.2 Comparación de Conjuntos La comparación de conjuntos en SQL, se realiza utilizando una sub consulta dentro de un comando select vinculadas las dos expresiones select por la cláusula some ó por la cláusula all. El mecanismo de comparación es el siguiente: el conjunto generado por la cláusula select principal se compara elemento a elemento con el conjunto generado por la sub consulta, el atributo ó los atributos involucrados en la comparación se determinan en la cláusula where del select principal y la forma de comparación depende de que si la cláusula a utilizar es some ó all. 5.6.2.1 Efecto de la cláusula some Sea x un elemento del conjunto generado por la cláusula select principal sean {Y1, Y2,...Yn} el conjunto generado por la subconsulta, sea comp una expresión de comparación; Entonces si existe Yi, i=1...n ∋ x comp Yi es verdadero para algún i entre 1 y n, la tupla donde se encuentra el valor x en la relación generada por la cláusula select principal será parte de la consulta. 2 Introducción a SQL Ejemplo: ♦ Sea X = {5,18,10,24,33,1} el conjunto principal de comparación (el generado por el select principal) ♦ Sea Y= {13,2,1,8,5,4,9} el conjunto definido por la sub consulta, sea comp la expresión <=, entonces X <= some Y es verdadero para los siguientes valores del conjunto X: 5,10,1 pues 5<13; 10 <13; 1<13, así mismo no se incluye a 18 por ejemplo pues no existe un elemento en Y tal que 18 sea <= a ese elemento. Ejemplo en SQL: “Obtener los nombres de todas las sucursales que poseen un activo mayor que al menos una sucursal situada en Granada”. ♦ Solución: select nombre_sucursal from Sucursal where activo >some (select activo from Sucursal where ciudad_sucursal= ‘Granada’) La sub consulta (select activo from Sucursal where ciudad_sucursal= ‘Granada’) genera el conjunto de todos los valores de activo para todas las sucursales situadas en Granada. La comparación >some, en la cláusula where de la cláusula select más externa, es verdadera si el valor del atributo activo de la tupla es mayor que al menos un miembro del conjunto de todos los valores de activo de las sucursales de Granada. SQL permite realizar las comparaciones <some, <=some, >=some, =some y <>some. Se puede notar que =some es equivalente a in, mientras que <=some no es lo mismo que not in. 5.6.2.2 Efecto de la cláusula all Esta cláusula compara dos conjuntos definidos de forma similar que en el caso de la cláusula some con la diferencia de que la tupla generada por la cláusula select principal será parte de la consulta de salida si la comparación X comp yi; i = 1...n es verdadera ∀ yi, i = 1... n Ejemplo: ♦ Sea x = {5,18,10,24,33,1} el conjunto generado por la cláusula select principal y sea Y={13,2,1,8,5,4,9} el conjunto definido por la subconsulta; sea comp la expresión >=, encontrar los elementos de x para los cuales x >=all Y es verdadero. Estos son: 18, 24, 33 pues 18 es mayor que todos los elementos del conjunto Y, igual ocurre con 24 y 33 por el contrario la desigualdad no es válida para 5 pues 5 no es mayor que todos los elementos en Y. La constructora >all corresponde a la expresión <<superior a todas>>. 3 Introducción a SQL Ejemplo en SQL: “Obtener los nombres de todas las sucursales que tienen un activo superior al de todas las sucursales de Granada”. ♦ Solución: select nombre_sucursal from Sucursal where activo >all (select activo from Sucursal where ciudad_sucursal= ‘Granada’) Al igual que some, SQL también permite utilizar las comparaciones <all, <=all, >=all, =all y <>all. Ejemplo: “Encontrar la sucursal que tiene el mayor saldo promedio”. Para resolver esta consulta utilizará la siguiente estrategia: Se formula una consulta para encontrar todos los saldos promedios y luego se anida ésta como subconsulta de una consulta que encuentre aquellas sucursales para las que el saldo promedio es mayor o igual que todos los saldos promedios. ♦ Solución: select nombre_sucursal from Cuenta group by nombre_sucursal having avg (saldo) >= all (select avg(saldo) from Cuenta group by nombre_sucursal) 5.6.3 Comprobación de relaciones vacías SQL incluye la posibilidad de comprobar si una sub consulta no produce ninguna tupla como resultado. La cláusula exists devuelve el valor Verdadero si la sub consulta argumento no es vacía. Ejemplo: “Encontrar todos los clientes que tienen tanto un préstamo como una cuenta en el banco” ♦ Solución: select id_cliente from Impositor where exists (select * from Impositor where Impositor.id_cliente = Prestatario.id_cliente) En este caso se revisarán cada una de las filas de Impositor de tal forma que si el valor del id_cliente en esa fila está en Impositor y Prestatario, entonces este valor es parte de la consulta. Utilizando la cláusula not exists se puede comprobar la inexistencia de tuplas en el resultado de una sub consulta. Además se puede utilizar la constructora not exists para simular la operación de continencia de conjuntos (es decir, superconjunto). Así, se puede escribir la expresión <<>la relación A contiene la relación B>> como <<not exists (B except A)>>. 4 Introducción a SQL 5.7 MODIFICACIÓN DE LA BASE DE DATOS SQL posee comandos destinados también para modificar la base de datos, entre estos se tienen operaciones de borrado, inserción y actualización. 5.7.1 BORRADO La operación de borrado se expresa de igual manera que una consulta. Se pueden borrar sólo tuplas completas, es decir, no se pueden borrar valores de atributos concretos. La expresión SQL relacionada con el borrado es: ♦ delete * from r where p Donde r es una relación y p es una condición lógica que determina las tuplas a ser eliminadas de r, si la condición p es omitida, se eliminan todas la tuplas de r. Hay que señalar que una orden delete opera sólo sobre una relación. Si se desea borrar tuplas de varias relaciones, se deberá utilizar una orden delete por cada relación. El predicado de la cláusula where puede ser tan complicado como el where de cualquier cláusula select, o tan simple como una cláusula where vacía. Ejemplo: Borrar todas las tuplas de la relación Prestamo (Los sistemas bien diseñados requerirán una confirmación del usuario antes de ejecutar una consulta como esta). ♦ Solución: delete from Prestamo Ejemplo: Borrar todas las cuentas de la Sucursal ‘Subtiava’ ♦ Solución: delete from Cuenta where nombre_sucursal=’Subtiava’ Ejemplo: Borrar todos los préstamos en los que el monto del préstamo esté entre C$ 5,000 y C$ 10,000 córdobas. ♦ Solución: delete from Prestamo where importe between 5000 and 10000 Ejemplo: Borrar las cuentas de todas las sucursales de Granada En este caso la solución se genera mediante una subconsulta que muestra los nombres de las sucursales ubicadas en Masaya. De modo que la expresión SQL requerida es: ♦ Solución: delete from Cuenta where nombre_sucursal in (select nombre_sucursal from Sucursal where ciudad_sucursal = ’Granada’) 5 Introducción a SQL En este borrado se selecciona primero todas las sucursales con sede en Granada y a continuación borra todas las tuplas Cuenta pertenecientes a esas sucursales. 5.7.1.1 Uso de funciones de agregación en una subconsulta de borrado. Ejemplo: Borrar todas las cuentas cuyos saldos sean inferiores a la media del banco ♦ Solución: delete from Cuenta where saldo <(select avg (saldo) from Cuenta) La orden delete comprueba primero que cada tupla de la relación Cuenta tiene un saldo inferior a la media del banco. A continuación se borran todas las tuplas que cumplan la condición anterior, es decir, las que representan una cuenta con un saldo menor que la media. Es importante realizar todas las comprobaciones antes de llevar a cabo el borrado. 5.7.2 INSERCIÓN El comando SQL encargado de realizar la inserción de una ó más tuplas en una relación es el comando insert, este tiene dos variantes: ♦ Una para insertar una sola tupla indicando los valores de los atributos de forma explícita, la forma general en este caso es insert into r values (tupla a insertar) en el caso de que se respete el orden de los atributos en la relación r, ♦ En caso de que la tupla a insertar no respete ese orden, el nombre de los atributos se debe listar también en el comando insert. Para insertar datos en una relación, o bien se especifica la tupla que se desea insertar o se formula una consulta cuyo resultado sea el conjunto de tuplas que se desean insertar. Obviamente, los valores de los atributos de las tuplas que se inserten deben pertenecer al dominio de los atributos. De igual manera, las tuplas insertadas deberán ser de la aridad correcta. La instrucción insert más sencilla corresponde a la de inserción de una tupla. Ejemplo: Insertar en la base los datos asociados a la cuenta C-0045 en la Sucursal Léon y que tiene como saldo C$ 6000.00 ♦ Solución Caso 1: insert into Cuenta values ( ’C-0045’, ’León’, 6000) En este ejemplo los valores se especifican en el mismo orden en que los atributos se listan en el esquema de la relación Cuenta. Para beneficio de los usuarios que no pueden recordar el orden de los atributos se especifican en la cláusula insert. 6 Introducción a SQL ♦ Solución Caso 2: insert into Cuenta (nombre_sucursal, numero_cuenta, saldo) values (’León’,’C-0045’,6000) ♦ Solución: insert into Cuenta (numero_cuenta, nombre_sucursal, saldo) values (’C0045’,’León’,6000) El efecto es similar al ejemplo anterior con la diferencia de que se han listado explicitamente los nombres de los atributos, esto debido a que en la cláusula values no se ha guardado el orden que estos tienen en la estructura de la tabla. ♦ Generalmente se desea insertar las tuplas que resultan de una consulta. Ejemplo: Si a todos los clientes que tienen un préstamo en la sucursal Subtiava se les quisiera regalar, como gratificación una cuenta de ahorro con C$ 5000.00 por cada cuenta de préstamo que posee. ♦ Solución: insert into Cuenta select nombre_sucursal,numero_prestamo, 1000 from Prestamo where nombre_sucursal = ‘Subtiava’ La instrucción select se evalúa primero, produciendo un conjunto de tuplas que a continuación se insertan en la relación Cuenta. Cada tupla tiene un nombre_sucursal (Subtiava), un numero_prestamo (que sirve como número para la nueva cuenta) y un saldo inicial de la cuenta (C$ 1000). Es necesario añadir tuplas a la relación Impositor, a través de la siguiente consulta: ♦ Solución: insert into Impositor select nombre_cliente, numero_prestamo from Prestatario, Prestamo where Prestatario.numero_prestamo = Préstamo.numero_prestamo and nombre_sucursal = ‘Subtiava’ Esta consulta inserta en la relación Impositor una tupla (nombre_cliente, numero_prestamo) por cada nombre_cliente que posea un préstamo en la sucursal Subtiva, con número de préstamo numero_prestamo. 5.7.3 ACTUALIZACIONES En determinadas situaciones puede ser necesario cambiar un valor dentro de una tupla, sin cambiar todos los valores de la misma. Para este tipo de situaciones se utiliza la instrucción update. Al igual que ocurre con insert y delete, se puede elegir las tuplas que van a ser actualizadas mediante una consulta. Forma general: Sea r una relación y sea exp la expresión de actualización, entonces la forma general del comando de actualizaciones: 7 Introducción a SQL ♦ update r set exp Ejemplo: Realizar el pago de intereses anuales y todos los saldos se incrementen en un 5%, habría que formular la siguiente consulta de actualización: ♦ Solución: update Cuenta set saldo=saldo * 1.05 Esta actualización se aplica una vez a cada tupla de la relación Cuenta. Ejemplo: Si se paga el interés sólo a las cuentas con un saldo de C$ 1000 o superior, se puede escribir la siguiente consulta. ♦ Solución: update Cuenta set saldo = saldo * 1.05 where saldo >=1000 En general la cláusula where de la instrucción update puede contener cualquier constructor legal en la cláusula where de una instrucción select (incluyendo instrucciones select anidadas). Ejemplo: Pagar un interés del 5% a las cuentas cuyo saldo sea mayor que la media. ♦ Solución: update Cuenta set saldo=saldo * 1.05 where (saldo > select avg(saldo) from Cuenta) Ejemplo: Suponer que las cuentas con saldos superiores a C$ 5000 reciben un 6% de interés, mientras que las demás cuentas recibirán un 5%. ♦ Solución: update Cuenta set saldo = saldo + (saldo * 0.06) where saldo > 5000 ♦ Solución: update Cuenta set saldo = saldo + (saldo * 0.06) where saldo <= 5000 Tomar en cuenta, que el orden en el que se ejecutan dos instrucciones de actualización es importante. Este tipo de solución tiene el inconveniente de que si se modifica el orden de las consultas de actualización se pueden generar actualizaciones erróneas. Así si se realiza primero el incremento del 5%, valores cercanos a 1000 pasarían a ser valores mayores de 1000 con lo cual se les aplicaría el 6% de incremento, llegándose a un incremento neto del 1.05 * 1.06 = 1.113 es decir el 11.3%, en lugar del 5% para evitar esta problemática SQL cuenta con el comando case muy similar al comando de los lenguajes de propósito general, así la expresión del ejemplo anterior utilizando case es: SQL ofrece una constructora case, que se puede usar para formular las dos instrucciones de actualización en una instrucción de actualización. 8 Introducción a SQL ♦ La forma general de la cláusula case es: case when pred1 then result1 when pred2 then result2 … when predn then resultn else result0 end En este caso se analizan cada uno de los predicados y si predi es verdadero entonces se ejecuta resulti. Por otra parte si ninguno de los predicados es verdadero se ejecuta result0. Solución: update Cuenta set saldo = case when saldo <= 10000 then saldo * 1,05 else saldo * 1.06 end 5.8 TRANSACCIONES Una transacción es un conjunto de instrucciones SQL de consultas y actualizaciones que deben de ejecutarse todas de forma exitosa o no ejecutar ninguna. La norma SQL especifica que una transacción comienza de forma implícita (no hay comando de comienzo) cuando se ejecuta una instrucción SQL, la transacción finaliza con cualquiera de las siguientes opciones dependiendo de la decisión del usuario. Commit: Compromete la Transacción actual, es decir hace que los cambios realizados por la transacción sean permanentes en la base de datos. Después de ejecutarse este comando comienza una nueva transacción de forma automática RollBack: Su efecto es retroceder la transacción actual es decir deshace todas las actualizaciones realizadas por las instrucciones SQL, de tal forma que la base de datos se restaura al estado que existía previo a la primera instrucción de la transacción. 9