SGBD5 SQL
SGBD5 SQL
SGBD5 SQL
5.1.- Introduccin Los SBD comerciales necesitan un lenguaje de consultas cmodo para el usuario. En este captulo se estudia el lenguaje comercial de mayor influencia, SQL. SQL usa una combinacin de lgebra relacional y construcciones del clculo relacional. Aunque el lenguaje SQL se considere un "lenguaje de consultas", contiene muchas otras capacidades adems de la consulta en BD. Incluye caractersticas para definir la estructura de los datos, para la modificacin de los datos en la BD y para la especificacin de ligaduras de seguridad. Las distintas implementaciones de SQL pueden diferenciarse en detalles, o pueden admitir slo un subconjunto del lenguaje completo. SQL se ha establecido claramente como el lenguaje estndar de BD relaciones. Hay numerosas versiones de SQL. La original se desarroll en IBM como parte del proyecto System R con el nombre Sequel a principios de 1970. Su nombre pas a ser SQL (Structured Query Languaje, Lenguaje estructurado de consultas). Actualmente, numerosos productos son compatibles con el lenguaje SQL. En 1986, ANSI e ISO publicaron una norma SQL, denominada SQL-86. En 1987, IBM public su propia norma: SAA-SQL (Systems Application Architecture Database) En 1989 se public una norma extendida para SQL denominada SQL-89 y actualmente los SBD son normalmente compatibles al menos con las caractersticas de SQL-89. La versin actual de la norma SQL ANSI/ISO es la norma SQL-92 y en trabajo se encuentra la SQL-3 El lenguaje tiene varios componentes:
Lenguaje de definicin de datos (LDD). El LDD de SQL proporciona ordenes para la definicin de esquemas de relacin, borrado de relaciones, creacin de ndices y modificacin de esquemas de relacin. Lenguaje interactivo de manipulacin de datos (LMD). El LMD de SQL incluye un lenguaje de consultas, basado tanto en el lgebra relacional como en el clculo relacional de tuplas. Incluye tambin ordenes para insertar, borrar y modificar tuplas de la BD. LMD incorporado. La forma incorporada de SQL se dise para el uso con lenguajes de programacin de propsito general, tales como PL/I, Cobol, Pascal, Fortran y C Definicin de vistas. El LDD de SQL incluye ordenes para la definicin de vistas. Autorizacin. el LDD de SQL incluye ordenes para la especificacin de los derechos de acceso a relaciones y vistas. Integridad. El LDD de SQL incluye ordenes para la especificacin de las ligaduras de integridad que deben satisfacer los datos almacenados en la BD. Las actualizaciones que violen las ligaduras de integridad se rechazan. Control de transacciones. SQL incluye ordenes para la especificacin de comienzo y final de transacciones. Varias implementaciones permiten tambin bloque explcito de los datos para el control de la concurrencia.
Lenguaje de Definicin de Datos Introduccin Las sentencias SELECT, INSERT y UPDATE se refieren a la manipulacin de datos de un BD. stas sentencias se le denominan lenguaje de manipulacin de datos de SQL o DML (Data Manipulation Language). Las sentencias DML pueden modificar los datos almacenados en una BD pero no pueden cambiar su definicin o estructura; ninguna de stas sentencias pueden crear o suprimir tablas. Los cambios de la estructura de una BD se realizan con un conjunto de sentencias SQL denominadas DDL (Data Definition Language). Con dicha sentencia podemos realizar lo siguiente: 1. Definir y crear una nueva tabla. 2. Suprimir una tabla existente. 3. Cambiar o modificar la definicin o structura de una tabla existente. 4. Definir o crear una tabla virtual o vista (view). 5. Establecer controles de seguridad para una BD. 6. Crear ndices (index) para realizar un acceso ms rpido a una tabla. 7. Tambin se pueden controlar donde se almacenan los datos, pudiendo variar bastante de un SGBD. Las tres sentencias bsicas del DDL son:
1. 2. 3.
CREATE: define y crea un objeto de la BD. DROP: elimina un objeto existente de la BD. ALTER: modifica la estructura de un objeto de la BD.
En un SGBD relacional se puede crear, eliminar o alterar las estructuras de las tablas de una BD, incluso mientras simultneamente proporciona acceso a la BD a sus usuarios. Esto significa que una BD relacional puede crecer y cambiar fcilmente en el tiempo. Aunque el DDL y DML son dos partes distintas del lenguaje SQL, en la mayora de los productos ambos lenguajes se entremezclan en aplicaciones de SQL programado y en sesiones de SQL interactivas. Creacin de una BD En grandes empresas el ABD es el nico responsable de la creacin de nuevas BD. En organizaciones ms pequeas, los usuarios individuales pueden tener permisos para crear sus propias BD personales, aunque lo ms normal es crear las BD centralizadamente y que luego puedan acceder usuarios individuales. En SQL Server una BD se crea de la siguiente forma: CREATE DATABASE <nombre_BD>, y luego nos pedir informacin sobre su tamao, ubicacin de ficheros,... Para borrar una BD se realiza DROP DATABASE <nombre_BD>. Creacin de una tabla Para crear una tabla en una BD se utiliza la sentencia CREATE TABLE <nombre_tabla>. Siempre antes de crear cualquier tabla hemos de decirle en que BD se va a crear. Para ello tenemos la sentencia USE <nombre_BD>. Primero se usa la BD, y luego se crea la tabla. En SQL Server siempre para ejecutar varios simultneos CREATE hemos de indicarlo con GO. La sentencia CREATE TABLE tiene la siguiente sintaxis: CREATE TABLE <nombre_tabla> (col1 tipo1 [NOT NULL] [UNIQUE] [PRIMARY KEY] [DEFAULT <valor>],... <restricciones_de_la_tabla>). Las restricciones se refieren a lo siguiente:
PRIMARY KEY (col1,...) FOREIGN KEY <llave_externa> REFERENCES <nom_tabla> (llave_primaria) Tambin se puede especificar en caso de que se borre o modifique que opciones tomar: [ON DELETE/UPDATE] CASCADE / SET NULL / SET DEFAULT valor / NO ACTION CHECK condicin: impone la condicin que debe cumplir cada tupla de la tabla. La condicin puede ser todo lo compleja que se quiera, incluso se pueden incluir subconsultas. Todas estas restricciones se imponen con la clusula CONSTRAINT. CREATE TABLE tabla_ejemplo (matricula INT NOT NULL, DNI VARCHAR (9) NOT NULL, Estatura DECIMAL (3,1), Activo BIT DEFAULT 1, PLUS AS estatura * 1.20, CONSTRAINT clave_tabla PRIMARY KEY (matricula), CONSTRAINT datos_dni FOREIGN KEY (dni) REFERENCES alumnos (dni), CONSTRAINT no_pasar CHECK estatura > 1.50) Crear en la BD SPJ2 las tablas proveedores2, piezas2, proyectos2 y suministros2. CREATE TABLE proveedores2 (IdS VARCHAR (3) NOT NULL, nombre VARCHAR (30) NOT NULL, status INT, ciudad VARCHAR (15), CONSTRAINT pk_s PRIMARY KEY (IdS)) GO CREATE TABLE piezas2 (IdP VARCHAR (3) NOT NULL, nombre VARCHAR (30) NOT NULL, ciudad VARCHAR (15), CONSTRAINT pk_p PRIMARY KEY (IdS)) GO CREATE TABLE proyectos2 (IdJ VARCHAR (3) NOT NULL, nombre VARCHAR (30) NOT NULL, ciudad VARCHAR (15), CONSTRAINT pk_j PRIMARY KEY (IdJ)) GO CREATE TABLE suministros2 (IdS VARCHAR (3) NOT NULL, IdP VARCHAR (3) NOT NULL, IdJ VARCHAR (3) NOT NULL, Cantidad NUMERIC (4,0), CONSTRAINT pk_spj PRIMARY KEY (IdS,IdP,IdJ) CONSTRAINT fk_s FOREIGN KEY (IdS) REFERENCES proveedores2 (IdS), CONSTRAINT fk_p FOREIGN KEY (IdP) REFERENCES piezas2 (IdP), CONSTRAINT fk_j FOREIGN KEY (IdJ) REFERENCES proyectos2 (IdJ))
Se pueden incluir incluso columnas calculadas. Para borrar una tabla se puede utilizar la sentencia DROP TABLE <tabla>. Creacin de ndices Un ndice (INDEX) es una estructura que proporciona un acceso rpido a las filas de una tabla en base a valores de una o ms columnas. Este realmente se puede conseguir en la creacin de tabla usando la restriccin UNIQUE: CREATE TABLE alumnos (dni VARCHAR (10) NOT NULL PRIMARY KEY, ape VARCHAR (25) NOT NULL, nombre VARHAR (12) NOT NULL, expediente VARCHAR (10) NOT NULL, CONSTRAINT indice_alumnos UNIQUE expediente) Otra forma: CREATE TABLE alumnos (dni VARCHAR (10) NOT NULL PRIMARY KEY, ape VARCHAR (25) NOT NULL, nombre VARHAR (12) NOT NULL, expediente VARCHAR (10) NOT NULL UNIQUE) La creacin de los ndices se debe hacer junto a la creacin de la estructura de las tablas, y as, evitar posibles colisiones al crear ndices y que la tabla tenga datos, pues si creamos un ndice nico por campo, y ste tiene valores no nicos, entonces la generacin del ndice dara un error. Su formato es el siguiente: CREATE [UNIQUE] INDEX <indice> ON <tabla> (columna) El ndice siempre se crea por defecto de menor a mayor y en columnas se pueden especificar ms de una columna separadas por comas. CREATE INDEX indice_nombre ON proveedores (nombre) CREATE INDEX indice_ejemplo ON alumnos (edad DESC, apellidos ASC) Si adems de nico queremos que el ndice no admita valores nulos se pondr lo siguiente: CREATE UNIQUE INDEX <indice> ON <tabla> (columna) WITH IGNORE_DUP_KEY Es una decisin del ABD el establecer los ndices oportunos para que el rendimiento de la BD no se vea afectado, pues el uso de ndices ralentiza la actualizacin de los datos. Depender pues de las consultas a realizar. Para borrar un ndice se pone la sentencia: DROP INDEX <indice>. Modificacin de la estructura de una tabla La sentencia ALTER TABLE permite realizar lo siguiente:
a) Aadir y eliminar una o varias columnas a una tabla. b) Cambiar el valor por defecto de una columna. c) Aadir o eliminar claves primarias, claves externas, restricciones UNIQUE y restricciones CHECK, ... Su formato es el siguiente: ALTER TABLE tabla ADD columna DROP columna ALTER columna ADD clave primaria ADD clave secundaria ADD restriccin UNIQUE ADD restriccin CHECK ALTER TABLE SPJ2 ALTER COLUMN IdS VARCHAR (4) ALTER TABLE SPJ2 ADD hora DATETIME, ADD fecha STR (dia) + / + STR (mes) + / + STR (ao) ALTER TABLE tabla DROP CONSTRAINT <restriccion> ALTER TABLE APJ2 ADD CONSTRAINT clave_nueva PRIMARY KEY (IdS, IdP, IdJ, dia, mes, ao) ALTER TABLE SPJ2 ADD CONSTRAINT no_mas_de_5000 CHECK cantidad <= 5000 Creacin de vistas (VIEW) Una vista es una tabla virtual en la BD cuyo contenido viene de una consulta. Para el usuario de la BD la vista aparece como una tabla real, con un conjunto de columnas y una fila de datos. Pero la realidad es que una vista no existe en la BD como un conjunto de valores almacenados, sino que los datos que vemos a travs de la vista son los resultados producidos por la consulta que define dicha vista. SQL crea la ilusin de la vista dndole a sta un nombre similar al nombre de cualquier tabla, y almacenando la definicin y estructura de la vista en la BD. CREATE VIEW datos_vendedores AS SELECT nombre, ciudad, region, cuota, vendedores.ventas FROM vendedores INNER JOIN oficinas ON oficina_rep = oficina CREATE VIEW piezas_rojas AS SELECT * FROM P WHERE color = rojo A las tablas que usan las vistas se les denomina tablas fuentes de la vista. Nota: una vez creada una vista se puede utilizar en una sentencia SELECT exactamente igual que en una tabla real. SELECT nombre FROM datos_vendedores WHERE ventas > cuota Para las vistas sencillas el SGBD construye cada fila sobre la marcha. Si la vista no es sencilla, entonces el SGBD construye una tabla temporal.
Ventajas de las vistas: Seguridad: cada usuario puede tener acceso a la BD a travs nicamente de un conjunto de vistas con los datos que el usuario est autorizado a ver restringiendo de sta forma el acceso del usuario a las datos almacenados. Simplicidad de consulta: una vista puede extraer datos de distintas tablas y presentarlos como una nica tabla y esto hace que consultas multitabla se puedan formular como consultas simples de una sola tabla con respecto a la vista. Las vistas permiten aislar a los usuarios frente a cambios que se puedan realizar de la estructura de la BD. Integridad de datos: si se introducen datos en la BD a travs de una vista, el SGBD puede comprobar automticamente los datos para asegurarse que satisfacen las restricciones de integridad especificadas. Inconvenientes de las vistas a la hora de utilizar una vista en lugar de una tabla real: Rendimiento: una vista lo que hace es crear la apariencia de una tabla, y por ello el SGBD debe traducir las consultas que se realicen en dicha vista en consultas reales a las tablas fuente, pudiendo ocurrir que se tardase mucho tiempo si la consulta fuese muy compleja. Restricciones de actualizacin: si un usuario quiere actualizar alguna fila de una vista entonces el SGBD tiene que traducir dicha peticin a una actualizacin de las filas de las tablas fuente. Esto slo es posible para vistas sencillas, y para vistas ms complejas es muy probable que no se puedan actualizar (se tratara de vistas de slo lectura). Conclusin: dependiendo de cada caso particular, el ABD decidir si se utiliza o no alguna vista. El diagrama sintctico para crear una vista es el siguiente: CREATE VIEW <vista> AS [nombre_columna,...] consulta sta sentencia asigna un nombre a la vista y especifica la consulta que define dicha vista. Para crear una vista con xito es necesario tener los permisos para acceder a todas las tablas referenciadas en la consulta. La sentencia CREATE VIEW puede asignar opcionalmente un nombre a cada columna en la vista recien creada. Si se hace es obligatorio poner el mismo nmero de elementos o columnas que las que produzca la consulta. Si se omite el nombre de las columnas de la vista cogern los de la consulta. Es obligatorio poner los nombre de las columnas de la vista si la consulta incluye columnas calculadas o si produce dos columnas con igual nombre. Bsicamente hay dos tipos de vistas, horizontales y verticales, aunque lo ms usual es definir una vista algo ms compleja donde intervienen parte horizontal y parte vertical de una o ms tablas, es decir, lo ms usual es definir una vista sobre muchas tablas (basada sobre una consulta multitabla). Vistas horizontales: se muestran ciertas filas o tuplas de una tabla. Crear una vista llamada vendedores 106 con los vendedores del director de cdigo 106. CREATE VIEW vendedores_106 AS SELECT * FROM vendedores WHERE director = 106 Crear la vista vendedores Este con los vendedores de la regin Este. CREATE VIEW vendedores_este SELECT * FROM vendedores WHERE oficina_rep IN (SELECT oficina FROM oficinas WHERE region = Este)
Vistas verticales: el uso de estas vistas es restringir el acceso de un usuario a solo ciertas columnas de una tabla. Crear la vista infor_ven que tenga el nmero de empleado, su nombre y la oficina de cada vendedor. CREATE VIEW infor_vend AS SELECT num_empl, nombre, oficina_rep FROM vendedores
Vistas agrupadas: son aquellas donde se incluye en la consulta una clusula GROUP BY. Las vistas agrupadas agrupan filas relacionadas de datos y producen una fila de resultados para cada grupo, resumiendo los datos de ese grupo. Crear la vista pedidos por vendedor, con los siguientes datos de pedidos sumario: cdigo del vendedor, nmero de pedidos realizados, suma de todos los importes, importe mnimo, importa mximo, media del importe. Adems la vista debe tener los siguientes nombres de columna: quien, cuntos, total, menor, mayor y medio. CREATE VIEW pedidos_por_vendedor (quien, cuantos, total, menor, mayor, medio) AS SELECT rep, COUNT (*), SUM (importe), MIN (importe), MAX (importe), AVG (importe) FROM pedidos GROUP BY rep Como podemos ver en el ejemplo, la definicin de una vista agrupada siempre incluir una una lista de nombres de columna. Una vez definida la vista se puede realizar cualquier consulta como si fuese una tabla real. Sacar el nombre, cantidad de pedidos, el importe total de pedidos, y el pedido medio para cada vendedor. SELECT nombre, cuantos, total, medio FROM pedidos_por_vendedor INNER JOIN vendedores ON quien = num_empl ORDER BY total DESC
Vistas compuestas: el motivo fundamental de utilizar vistas compuestas es simplificar las consultas multitabla en el caso de que se realicen con frecuencia un tipo o cierto tipo de consultas. Supongamos que el vicepresidente de ventas realiza frecuentes consultas sobre la tabla pedidos pero no quiere trabajar con nmero de cliente ni nmero de empleado, sino con los nombres de empleados y nombres de clientes. Quiere tener informacin del nmero de pedido, nombre del cliente, nombre del empleado y el importe. CREATE VIEW infor_pedidos AS SELECT num_pedido, empresa, nombre, importe FROM clientes INNER JOIN (pedidos INNER JOIN vendedores ON rep = num_empl) AS T ON num_clie = T.clie Posteriormente dicho vicepresidente de ventas podr saber la suma de los pedidos totales para cada empresa y para cada vendedor. SELECT vendedor, empresa, SUM (importe) FROM infor_pedidos GROUP BY nombre, empresa
Actualizacin de Bases de Datos Introduccin En el tema anterior hemos visto como realizar consultas de una BD utilizando SQL, ahora vamos a ver como se puede modificar y actualizar datos de la BD. El SGBD debe proteger la integridad de los datos durante los cambios, asegurndose de que se introduzcan datos vlidos, y que la BD permanezca autoconsistente, incluso en caso de fallo del sistema. Adems el SGBD debe coordinar tambin las actualizaciones simultneas por parte de mltiples usuarios, asegurndose que los usuarios y sus modificaciones no interfieran unos con otros. Hay un tema dedicado a esto, el procesamiento de transacciones. Vamos a ver las sentencias que utiliza SQL para modificar los contenidos de una BD: INSERT: para aadir nuevos filas a una tabla. DELETE: borra filas de una tabla. UPDATE: modifica datos existentes en una BD. Sentencia INSERT Se puede aadir una nueva fila de datos a una tabla, normalmente en programas de entrada de datos y se utiliza habitualmente en aplicaciones diarias. Tambin podemos extraer datos de una o varias tablas y aadirlos a otra tabla, y esto se utiliza habitualmente en procesos de fin de mes o de fin de ao. Y para finalizar una utilidad llamada de carga masiva aade datos a una tabla desde un fichero externo a la BD. Esto se utiliza habitualmente para cargar inicialmente la BD o bien para incorporar datos transferidos desde otro sistema informtico. Sentencia INSERT de una fila: se utiliza para aadir una nueva fila a una tabla. Su diagrama sintctico es el siguiente: INSERT INTO tabla (nom_columna1, nom_columna2,...) VALUES (valores constantes) Dar de alta un vendedor INSERT INTO vendedores (nombre, edad, num_empl, ventas, titulo, contrato, oficina_rep) VALUES (Henry Jo, 36, 111, 0, director de ventas, 10 Febrero 2003, 13) En el caso que no se quiera insertar valores en todas las columnas entonces se especificarn los nombres de las columnas para las que se quieren introducir datos. Si se quisiera introducir datos en todas las columnas no es necesario poner los nombres de las columnas. Adems asigna automticamente un valor null a cualquier columna cuyo nombre falte en la lista de columnas. En el ejemplo anterior le asigna un null a las columnas director y cuota. Insercin de todas las columnas: como hemos dicho se puede omitir la lista de columnas y de esta forma se genera automticamente una lista con todas las columnas en secuencia de izqda. a drcha. Usando esta forma abreviada en el ejemplo anterior tendremos: INSERT INTO vendedores VALUES (111, Henry Jo, 36, 13, director de ventas, 10 Febrero 2003, null, null, 0) La secuencia de valores debe corresponderse exactamente con la secuencia de valores de la tabla. La sentencia INSERT multifila: se utiliza para insertar de golpe una subtabla, correspondiente a una consulta SELECT, en otra tabla destino. INSERT INTO tabla_destino (nom_columna, ...) consulta INSERT INTO tabla_destino [(col1), (col2),...] SELECT lista FROM tablas WHERE condicin
Esto es til en alguna situacin especial. Supongamos que se desea copiar el nmero de pedido, la fecha y el importe de todos los pedidos remitidos con anterioridad al 1 de Enero de 1990, desde la tabla pedidos a otra tabla llamada ant_pedidos: INSERT INTO ant_pedidos (num_pedido, fecha_pedido, importe) SELECT num_pedidos, fecha_pedidos, importe FROM pedidos WHERE fecha_pedido < 01-Ene-90 Las columnas de la consulta y la lista de columnas deben ser del mismo tipo. Insertar en la tabla de proveedores el proveedor de cdigo S13, nombre Jimnez Travieso, Mara, de estatus 2 y ciudad Jan. INSERT INTO S (IdS, nombre, status, ciudad) VALUES (S13, Jimnez Travieso, Mara, 2, Jan) Sentencia DELETE La sentencia DELETE elimina filas de datos seleccionados de una nica tabla. DELETE FROM tabla (WHERE condicin) Sino se especifica WHERE condicin se eliminarn todas las filas de la tabla. Supongamos que el nuevo vendedor Henry Jo decide abandonar la empresa. DELETE FROM vendedores WHERE nombre = Henry Jo Supongamos que el cliente 2106 ha llamado para cancelar todos sus pedidos. DELETE FROM pedidos WHERE clie = 2106 Suprimir todos los pedidos remitidos antes del 15-11-89. DELETE FROM pedidos WHERE fecha_pedido < 15 NOV 89 Suprimir todas las filas correspondientes a los pedidos atendidos por 101, 105, 109. DELETE FROM pedidos WHERE rep IN (101, 105, 109) Suprimir todos los vendedores contratados antes de Julio de 1988 a los que an no se les ha asignado una cuota. DELETE FROM vendedores WHERE contrato < __ Jul. 88 AND cuota = null Supresin de todas las filas: si se omite la clusula WHERE de una clusula DELETE se suprimen todas las filas de la tabla destino. Suprimir todos los pedidos. DELETE FROM pedidos Lo que hace es borrar todas las filas de la tabla pero no borra la tabla, es decir, mantiene la definicin de la tabla y sus columnas aunque vacas. Para borrar una tabla se utiliza la sentencia DROP TABLE tabla.
DELETE con subcondulta: se pueden borrar una o varias filas segn cumplan o no alguna condicin. Borrar todos los pedidos del vendedor Sue Smith. DELETE FROM pedidos WHERE rep = (SELECT num_empl FROM vendedores WHERE nombre = Sue Smith) Suprimir los clientes atendidos por vendedores cuyas ventas son inferiores al 80% de su cuota. DELETE FROM pedidos WHERE rep = (SELECT num_empl FROM vendedores WHERE ventas < 0.8 * cuota) Suprimir los clientes que no han realizado pedidos desde el 10-11-1989. DELETE FROM clients WHERE num_clie = (SELECT clie FROM pedidos HAVING MIN (fecha_pedido) < 10 Nov. 89) DELETE tiene la siguiente restriccin: la tabla de la sentencia DELETE no puede aparecer en ningn FROM de la subconsulta.
Sentencia UPDATE La sentencia UPDATE modifica los valores de una o ms columnas en las filas seleccionadas en una tabla nica. UPDATE tabla SET (nom_col = expresin, ...) WHERE condicin La unidad mnima que se puede modificar es la columna de una tabla. Elevar el lmite de crdito de la empresa Acme Manufacturing a $60000 y adems reasignarla al empleado 109. UPDATE clientes SET limite_credito = 60000, rep_clie = 109 WHERE empresa = Acme Mfg Igual que ocurra con la sentencia DELETE la sentencia UPDATE puede actualizar varias filas de una vez. Transferir todos los vendedores de la oficina 12 a la oficina 11 y adems rebajar sus cuotas un 10%. UPDATE vendedores SET oficina_rep = 11, cuota = cuota*0.9 WHERE oficina_rep = 12 Reasignar todos los clientes atendidos por los empleados nmero 105, 106 o 107 al empleado nmero 102. UPDATE clientes SET rep_clie = 102 WHERE rep_clie IN (105,106,107) Asignar una cuota de $100000 a todos aquellos vendedores que actualmente no tienen cuota. UPDATE vendedores SET cuota = 100000 WHERE cuota IS null
La clusula SET es una lista de asignaciones separadas por comas donde en cada asignacin se actualiza una columna de la forma nombre_columna = <expresin>,... No debera haber dos asignaciones para la misma columna destino. La expresin debe generar un valor de un tipo de dato apropiado para la columna destino. Y sino se hace? En la expresin no se puede incluir funciones de columna ni subconsultas. Si en la expresin se hace referencia a alguna columna de la tabla destino, el valor utilizado para calcular la expresin es el valor de dicha columna en la fila actual antes de que se aplique ninguna actualizacin. Lo mismo se puede decir de las referencias de columna que se producen en la clusula WHERE. UPDATE vendedores SET cuota = 400000, ventas = cuota WHERE cuota < 360000 Antes de la actualizacin (ver tablas) el primer vendedor Bill Adams tena un valor de cuota de $350000 y ventas de $367911. Despus de la actualizacin su fila tendr un valor de ventas es de $350000 (coge el valor de cuota antes de actualizarlo) y la cuota ser de $400000. Se puede deducir que el orden de las asignaciones de la clusula SET no es significativo, da igual el orden. Actualizacin de todas las filas: si se omite la clusula WHERE entonces se actualizan todas las filas de la tabla destino. Elevar todas las cuotas de los vendedores un 5%. UPDATE vendedores SET cuota = cuota + cuota*0,05 A diferencia de DELETE, en donde la clusula WHERE casi nunca se omite, la sentencia UPDATE sin la clusula WHERE realiza una funcin muy til, la actualizacin masiva de toda la tabla. Ver ejemplo anterior Update con Subconsultas: al igual que ocurra con DELETE las subconsultas juegan un papel importante en la sentencia UPDATE, pues permiten seleccionar las filas que se quieren actualizar. Incrementar en $5000 el lmite de crdito de aquellos clientes que tengan algn pedido con importe superior a $25000. UPDATE clientes SET limite_credito = limite_credito + 5000 WHERE num_clie IN (SELECT clie FROM pedidos WHERE importe > 25000) Reasignar al vendedor 105 todos los clientes atendidos por vendedores cuyas ventas son inferiores al 80% de sus cuotas. UPDATE pedidos SET rep = 105 WHERE rep IN (SELECT num_empl FROM pedidos WHERE ventas < cuota * 0.8) Hacer que los vendedores que atiendan a ms de tres clientes estn bajo las rdenes del vendedor 106, es decir, que su director sea el vendedor 106. UPDATE vendedores SET director = 106 WHERE num_empl IN ( SELECT rep FROM pedidos ORDER BY rep
HAVING COUNT (clie) > 3) Igual que con DELETE las subconsultas de UPDATE se pueden anidar a cualquier nivel, y tambin pueden contener referencias externas a la tabla destino de la sentencia UIPDATE. Ver ejercicio anterior. Hay una restriccin en la sentencia UPDATE y es que la tabla destino no puede aparecer en la clusula FROM de ninguna subconsulta a ningn nivel de anidacin. Motivo: que algunas de sus filas pueden ya haber sido actualizadas.
USE AdventureWorks; GO UPDATE Sales.SalesPerson SET SalesYTD = SalesYTD + (SELECT SUM(so.SubTotal) FROM Sales.SalesOrderHeader AS so WHERE so.OrderDate = (SELECT MAX(OrderDate) FROM Sales.SalesOrderHeader AS so2 WHERE so2.SalesPersonID = so.SalesPersonID) AND Sales.SalesPerson.SalesPersonID = so.SalesPersonID GROUP BY so.SalesPersonID); GO Si necesita utilizar TOP para aplicar actualizaciones por un orden cronolgico, debe utilizarla junto con ORDER BY en una instruccin de subseleccin. En el siguiente ejemplo se actualizan las horas de vacaciones de los 10 empleados cuyas fechas de alta son ms antiguas.
Copiar cdigo
UPDATE HumanResources.Employee SET VacationHours = VacationHours + 8 FROM (SELECT TOP 10 EmployeeID FROM HumanResources.Employee ORDER BY HireDate ASC) AS th WHERE HumanResources.Employee.EmployeeID = th.EmployeeID; GO
Lenguaje de Manipulacin de Datos Introduccin Todo lo referente a SQL lo podemos encontrar en l capitulo 7 Implementacin Relacional con SQL del libro Diseo y Administracin de BD. Vamos a trabajar con el mismo esquema de relaciones que hemos utilizado en la relacin del lgebra relacional. vendedores (num_empl, nombre, edad, ventas, titulo, contrato, oficina_rep) VALUES (111, Henry Jo, 36, 0, director de ventas, 10 Febrero 2003, 13)
Consultas Todas las consultas en SQL se utilizan usando el comando SELECT cuya sintaxis es la siguiente: SELECT lista de objetos FROM lista de tablas WHERE condicin Donde lista de tablas es la lista de los nombres de las tablas que intervienen en la consulta separadas por comas. Pueden existir alias asociados a las tablas, los cuales se declaran a continuacin del nombre de la tabla separados al menos por un espacio en blanco FROM Proveedor PRO, Piezas PIE La lista de objetos es una sucesin de tems separados por comas, que pueden ser: 1. Atributos de las tablas implicadas. 2. Valores calculados. 3. Literales o cadenas de caracteres. En los valores calculados se pueden usar operadores matemticos y agregacin de las que dispone SQL: 1. COUNT (): cuenta el nmero de elementos (contador). 2. SUM (): suma el valor de un atributo (acumulador). 3. MAX (): devuelve el valor mximo de un atributo. 4. MIN (): devuelve el valor mnimo de un atributo. 5. AVG (): devuelve la media de un atributo. tambin las funciones de
En la clusula SELECT el asterisco significa sacar todos los atributos y se utiliza bastante. Cul es la tarifa semanal de cada electricista? SELECT nombre, Tarifa Semanal, 40*tarifa_hora FROM trabajador WHERE tipo = electricista Por ahora el formato ms completo de SELECT quedara de la siguiente forma: SELECT tem seleccionado
ALL FROM
, tem seleccionado
DISTICNT * tabla , tabla WHERE condicin DISTINCT se pone cuando no quiera sacar los repetidos. Si en SELECT no se dice nada, saldrn todos, incluidos los repetidos. As pues, si quiero que no salgan repetidos tendr que poner: SELECT DISTINCT atributo FROM tabla Seleccionar aquellos trabajadores con una tarifa por hora entre 10 y 22. SELECT * FROM trabajadores WHERE tarifa_hora > 10 AND tarifa_hora < 22 Un poco de historia SQL viene del ingls Structured Query Language (Lenguaje de Consulta Estructurado). Los lenguajes relacionales surgen como resultado del lgebra y del clculo relacional. SQL fue el resultado del proyecto de investigacin System R de IBM. A finales de los 70 SQL pas al dominio pblico y se us como lenguaje de consulta para un sistema comercial de ORACLE Corp. En 1981 IBM lanz su SQL/DS, un sistema gestor de BD relacional que soporta SQL. En 1983 IBM lanz SQL como lenguaje de su SGBD DB2. En 1986 se aprueba el primer estndar ANSI para SQL que ha sido revisado posteriormente en 1989 y de forma especial en 1992. SQL ha quedado como el nico lenguaje relacional que es ANSI estndar. Actualmente hay muchas versiones de SQL para ordenadores personales y para arquitecturas cliente servidor, como son Sybase SQL Server, Microsoft SQL Server, IBM OS / 2 Extended Edition Database Manager, DFC Rdb / VMS, Oracle Server. SQL se utiliza adems de cmo lenguaje de consulta tambin para definir las tablas, actualizar las BD y otorgar privilegios. Por otra parte los SGBD relacionales incluyen aspectos de seguridad e integridad. Condiciones Adems de los operadores relacionales (=, <>, >, <, <=, >=) tenemos los operadores LIKE y BETWEEN. El operador LIKE permite la bsqueda de subcadenas en cadenas de caracteres. Pueden utilizar comodines que son % y _, que significan * y ? dentro del entorno de MS-DOS respectivamente. Ejemplo: SELECT nombre FROM proveedores WHERE nombre LIKE %el ste ejemplo saca todos los nombres, incluidos los repetidos. Qu hacer para sacar los nombres que no estn repetidos? SELECT DISTINCT nombre FROM proveedores WHERE nombre LIKE %el Otro operador que se puede utilizar es BETWEEN para comparar dos cantidades. Ejemplo: sacar aquellos trabajadores que tengan una tarifa por horas entre 10 y 22. SELECT *
FROM trabajadores WHERE tarifa_hora BETWEEN 10 AND 22 Ejemplo: sacar el nombre del vendedor, ventas, cuota y la cuanta de cada vendedor que est por encima o por debajo de su cuota. SELECT nombre, ventas, cuota, (ventas cuota) FROM vendedores WHERE ventas < cuota Ejemplo: sacar el importe medio de todos los pedidos realizados por el cliente 2103. SELECT AVG (importe) FROM pedidos WHERE clie = 2013 Adelantando algo de SQL podemos ver como podramos borrar tuplas de una tabla. Ejemplo: borrar de la tabla clientes la empresa Rico Enterprises. DELETE FROM clientes WHERE empresa = Rico Enterprises Ejemplo: insertar una nueva oficina en Dallas en la regin Oeste cuyo objetivo va a ser $270000 y el nmero de oficina 23. INSERT INTO oficinas (ciudad, regin, objetivo, oficina, ventas) VALUES (Dallas, Oeste, $270000, 23, 0) Operador de pertenencia a un conjunto El operador que se utiliza es el operador IN que lo que hace es examinar si un determinado valor coincide con uno de una lista de valores. Ejemplo: sacar nombre, cuota y ventas de aquellos vendedores que trabajan en New York, Atlanta o Denver, cuya oficina a la que pertenece es la 11, 13 o 22. SELECT nombre, cuota, venta FROM vendedores WHERE oficina IN (11, 13, 22) Resumen Podemos renombrar columnas con el operador As al ponerlo despus de unos datos (en la lnea de Select) renombramos la nueva columna. Podemos concatenar nombres (en la columna Select) poniendo un nombre de columna seguido de cualquier palabra encerrada en comillas . Si al introducir una nueva fila, no le damos un valor a uno de los campos se pone automticamente a nulo. Para saber si un campo es nulo, se hacen las siguientes preguntas: Is Null Is Not Null Solo saldrn tuplas si la condicin de la clusula Where es verdadera. La clasula In nos permite saber si un determinado valor pertenece a un conjunto de valores. Sacar los suministros realizados por los proveedores segn S1 o S2. SELECT * FROM SPJ WHERE IdS IN (S1,S2,S3) Otra forma de hacerlo sera sustituir la ltima lnea por IdS = S1 OR IdS = S2 OR IdS = S3.
La clasula LIKE nos permite hacer comparaciones con cadenas de texto usando los comodines % y _. El % sustituye a una cadena de caracteres. El _ sustituye un solo carcter. Seleccionar el nombre de todos los proveedores. SELECT nombre FROM S WHERE nombre LIKE J% Seleccionar aquellos proveedores de Almera usando el comodn _ sobre . SELECT * FROM S WHERE Ciudad LIKE Almer_a Y si adems quisiramos incluir en la cadena de bsqueda el carcter % o _ tendramos que especificar una clasula escape en la clasula. Seleccionar las filas en las que el nombre comience en ant y tenga en medio de la cadena an. SELECT * FROM S WHERE nombre LIKE ant#%an% ESCAPE # Usando los corchetes, y dentro dos caracteres puede coger cualquiera de los dos caracteres para sustituirlo en un smbolo de _. Si nos encontramos con unos corchetes y dos caracteres separados por un guin, significa que puede coger en un _ cualquier carcter de los incluidos en los corchetes ([a-f] = coge desde la a hasta la f). El operador [^a-f] significa lo contrario del anterior. Operadores de comparacin ANY / ALL Hemos visto que el operador In comprueba si un valor es igual a alguno de los valores de una subconsulta. Los operadores Any y All comparan tambin un determinado valor con los valores producidos por una subconsulta con el siguiente formato: Valor (=, <>, >, >=, <, <=) ANY / ALL Subconsulta Any se usa conjuntamente con uno de esos seis operadores de comparacin. Veamos un ejemplo. Encontrar el nombre de los vendedores que han aceptado algn pedido cuyo importe represente ms del 10% de su cuota. SELECT nombre FROM vendedores WHERE cuota*0,10 < ANY (SELECT importe FROM pedidos WHERE rep = num_empl) El resultado sera Sam Clark, Larry Fitch y Nancy Angeli. Conceptualmente la consulta examina cada tupla o cada fila de la tabla vendedores una a una. La subconsulta encuentra todos los pedidos realizados o acertados por el vendedor actual y devuelve una columna que contiene los importes de esos pedidos. La clasula Where de la consulta principal calcula el 10% de la cuota del vendedor actual y el resultado lo compara con todos los importes producidos en la anterior subconsulta. Si hay algn importe que exceda al valor calculado (cuota * 0,1) entonces el test < Any devuelve TRUE y el vendedor queda incluido en los resultados de la consulta, sino el vendedor no se incluye.
El operador Any puede ser difcil de entender, ya que afecta a un conjunto de comparaciones, no slo a una. Si tenemos lo siguiente Where x < Any (Select y ...) donde x es menor a cualquier y seleccionado, se puede leer de otra forma: en donde para algn y, x es menor que y. Usando ste truco la consulta anterior pasa a ser la siguiente: Seleccionar los nombres de aquellos vendedores donde, para algn pedido realizado o aceptado por el vendedor, el 10% de la cuota del vendedor es menor al importe del pedido. Al igual que con Any se utiliza conjuntamente por los operadores relacionales, para comparar un nico valor con una columna de valores producida por una subconsulta, comparando ese valor con todos y cada uno de los valores del conjunto. Si todas las comparaciones individuales producen un resultado TRUE, entonces el test All devuelve un resultado TRUE. Ej.: sacar el cdigo de la oficina, la ciudad y su objetivo de aquellas oficinas donde todos los vendedores tienen ventas que superen el 50% del objetivo de la oficina. SELECT oficina, ciudad, objetivo FROM oficinas WHERE objetivo * 0,50 < ALL (SELECT ventas FROM vendedores WHERE oficina = oficina_rep) Los resultados son oficina, ciudad y objetivo (22, Denver, 300000; 22, Nueva York, 575000 ; 13, Atlanta, 350000). Si tenemos Where x < All (Select y ...) Es mucho mejor leerlo de otra forma: donde, para todo y, x es menor que y. Con este truco quedara el enunciado: Seleccionar las oficinas en donde para todos los vendedores que trabajan en esa oficina, el 50% de objetivo de la oficina es menor que las ventas del vendedor. Operadores relacionales (=, <>, <, >, >=, <=) Se puede comparar directamente el valor de una expresin con el valor producido por una consulta devolviendo TRUE si la comparacin es cierta. ste test se utiliza para comparar un valor de la fila que est siendo examinada con un valor nico producido por una subconsulta. Encontrar los nombres de aquellos vendedores cuyas cuotas son iguales o superiores al objetivo de la oficina de Atlanta. SELECT nombre FROM vendedores WHERE cuota >= (SELECT objetivo FROM oficinas WHERE ciudad = Atlanta) El resultado es Bill Adams, Sue Smith y Larry Fitch. Si la subconsulta produjese varias filas, la comparacin no tendra sentido. Si la consulta no produce filas o produce un valor null el test de comparacin produce un nulo. Sacar los nombres de aquellas empresas (clientes que son atendidas por Bill Adams). SELECT empresa FROM clientes WHERE rep_clie = (SELECT num_empl
FROM vendedores WHERE nombre = Bill Adams) Ordenacin de los resultados de una consulta. Clasula ORDER BY sta clasula se coloca al final del Select (la consulta) y su formato podra ser el siguiente: Order By nombre_col [Asc/desc], nombre_col [Asc/Desc],... De una forma ms elegante el diagrama sintctico sera el siguiente: Order By --------- nombre_columna ------------------------------#_columna Asc / Desc Por defecto, sino se pone nada se ordena de forma ascendente de menor a mayor. Mostrar la ciudad, regin y ventas de cada oficina ordenadas alfabticamente por regin, y dentro de cada regin ordenada por la ciudad. SELECT ciudad, regin, ventas FROM oficinas ORDER BY regin, ciudad Listar las oficinas (oficina, ciudad, regin, ventas) clasificadas en orden descendente de ventas. SELECT oficina, ciudad, regin, ventas FROM oficinas ORDER BY ventas DESC Siempre se podr poner el nombre de la columna o el nmero que ocupa en la lista de seleccin, teniendo en cuenta que el primer elemento es el nmero uno (de la consulta), pero si se trata de una columna calculada, que no tiene nombre, entonces se tiene que poner el nmero de dicha columna. Sacar la ciudad, regin y el rendimiento (ventas objetivo) de todas las oficinas, en orden descendente de rendimiento de ventas. SELECT ciudad, regin, ventas objetivo FROM oficinas ORDER BY 3 DESC Lo mismo que antes pero sacar las oficinas en orden alfabtico por regin, y dentro de cada regin en orden descendente de ventas. SELECT ciudad, regin, ventas objetivo FROM oficinas ORDER BY regin ASC, 3 DESC
Funciones de columna SQL permite resumir datos de la BD mediante un conjunto de funciones de columna. Una funcin de columna acepta una columna completa de datos de una tabla como argumento, y devuelve un nico dato resumen de dicha columna.
Por ejemplo, la funcin de columna AVG () calcula la media aritmtica o promedio de todos los datos de una columna. Cual es la cuota promedio y las ventas promedio de los vendedores. SELECT AVG (cuota), AVG (ventas) FROM vendedores SQL tiene las siguientes funciones de columna: SUM (), AVG (), MIN (), MAX (), COUNT (), COUNT (*). SUM calcula el total de una columna. AVG calcula el valor promedio de una columna. MIN devuelve el valor ms pequeo de una columna. MAX devuelve el valor mayor de una columna. COUNT cuenta el nmero de valores de una columna. COUNT * cuenta las filas de una consulta. El argumento de una funcin columna puede ser una columna o bien una expresin. Ej.: entendemos rendimiento de cuota como (ventas/cuota)*100. Cul es el rendimiento de cuota promedio de los vendedores? AVG (100*(ventas/cuota). Para procesar sta consulta, SQL construye una columna temporal con la expresin por cada fila de la tabla vendedores, y luego calcula los promedios de dicha columna temporal. 1. Clculo del total de una columna (SUM ()). La funcin de columna SUM () calcula la suma de una columna de datos que tienen que ser del tipo numrico: entero, decimal, flotante o monetario. Cuales son las cuotas totales y las ventas totales de todos y cada uno de los vendedores. SELECT SUM (cuota), SUM (ventas) FROM vendedores Cul es el total de los pedidos realizados por el vendedor Bill Adams? SELECT SUM (importe) FROM pedidos, vendedores WHERE nombre = Bill Adams AND rep = num_empl 2. Clculo del promedio de una columna (AVG ()). La funcin de columna AVG () calcula el promedio de una columna de datos que evidentemente tienen que ser numricos. Calcular el precio medio de los productos del fabricante ACI. SELECT AVG (precio) FROM productos WHERE id_fab = ACI Calcular el promedio de los pedidos realizados por el cliente nmero 2103. SELECT AVG (importe) FROM pedidos WHERE clie = 2103 Calcular el importe medio realizado por el cliente Acme Mfg. SELECT AVG (importe) FROM pedidos WHERE clie = (SELECT num_clie FROM clientes WHERE empresa = ACME Mfg.) SELECT AVG (importe) FROM pedidos, clientes
WHERE empresa = ACME Mfg. AND num_clie = clie 3. Valores extremos. Las funciones de columna MIN y MAX devuelven los valores menor y mayor de una columna. Los datos pueden ser numricos, cadenas o bien fecha / hora. Cuales con las cuotas mxima y mnima asignadas a los vendedores? SELECT MAX (cuota), MIN (cuota) FROM vendedores Cul es la fecha de pedido ms antigua de la BD? SELECT MIN (fecha_pedido) FROM pedidos Cul es el mejor rendimiento de ventas de todos los vendedores? (100*ventas/cuota) SELECT MAX (100*ventas/cuota) FROM vendedores 4. Contador de datos. La funcin de columna COUNT () cuenta el nmero de valores de datos que hay en una columna, que puede ser de cualquier tipo. Siempre devuelve un entero. Cuntos clientes hay? SELECT COUNT (num_clie) FROM clientes Cuantos vendedores superan su cuota? SELECT COUNT (num_empl) FROM vendedores WHERE ventas > cuota Cuntos pedidos hay con importe superior a 25000? SELECT COUNT (num_pedido) FROM pedidos WHERE importe > 25000 Se puede observar que COUNT ignora los valores de las columnas. Simplemente cuenta los valores que hay, por lo tanto en el ltimo ejemplo podramos haber puesto en vez de num_pedidos, importe. Por esto se podra utilizar la funcin especial con *, que cuenta filas en lugar de valores. 5. Consideraciones finales. Una funcin columna puede aparecer en la lista de seleccin en cualquier lugar, incluso puede formar parte de una expresin que sume o reste los valores de dos funciones de columna. Por otra parte el argumento de una funcin de columna nunca podr ser otra funcin de columna, ya que la expresin resultante no tendra sentido. Es ilegal anidar funciones de columna. Tambin es ilegal mezclar funciones de columna y nombres de columna ordinarios en una lista de seleccin, pues no tendra sentido la consulta resultante. SELECT nombre, SUM (ventas) FROM vendedores El primer tem de la seleccin genera una tabla con 10 filas, y el segundo tem genera una columna de una fila, que representa la suma de las diez ventas, por lo que los dos elementos SELECT se contradicen el uno con el otro produciendo un error. Los valores null son ignorados por las funciones de columna SUM (), AVG (), MAX (), MIN (), COUNT (). SELECT COUNT (*), COUNT (ventas), COUNT (cuota)
FROM vendedores El resultado son 10 filas, 10 filas y nueve filas respectivamente. La tabla vendedores tiene diez filas, por lo que COUNT (*) devuelve 10. La columna ventas tiene diez valores no nulos, por lo tanto devuelve 10. La columna cuota como tiene un null, entonces devuelve 9. Si se ignoran los valores null en las funciones de columna MAX () / MIN () no pasa nada. Sin embargo si puede ser importante para SUM () y AVG (). SELECT SUM (ventas), SUM (cuota), SUM (cuot) SUM (ventas), SUM (cuota ventas) FROM vendedores En la tercera columna saldrn como resultado 193532, y en la cuarta 117547. Por qu no sale el mismo valor? Porque hay valores null. El estndar ANSI especifica las siguientes reglas para gestionar los valores null en la funcin de columna: Si alguno de los valores de datos es null, se ignora para el clculo de la funcin de columna. Si todos los datos de una columna son null, las funciones de columna SUM (), AVG (), MAX () y MIN () devuelven un valor null. Sin embargo la funcin COUNT () devuelve un cero. Si no hay datos en la columna (vaca) entonces las cinco funciones devuelven un cero. La funcin COUNT (*) cuenta filas, y por lo tanto no depende de la presencia o ausencia de valores null en la columna. Slo si no hay filas devolver un cero. Para eliminar los valores duplicados de una columna se pondr la palabra clave DISTINCT delante del argumento de la funcin de columna. SELECT COUNT (titulo) FROM vendedores sta consulta devuelve un diez, por lo tanto si quisiramos saber cuntos ttulos diferentes tienen los vendedores deberamos hacer lo siguiente: SELECT COUNT (DISTINCT titulo) FROM vendedores Cuntas oficinas de ventas tienen vendedores que superen sus cuotas? SELECT COUNT (DISTINCT oficina_rep) FROM vendedores WHERE ventas > cuota DISTINCT () no tiene sentido ni para MIN () ni para MAX (). DISTINCT () no puede ser especificado con COUNT (*). DISTINCT () slo se puede especificar una vez en una funcin de columna de una consulta. Cuntas unidades se han suministrado de la pieza P1? SELECT SUM (unidades) FROM SPJ WHERE IdP = P1 Cul es el peso total de las piezas de Londres? SELECT SUM (peso) FROM P WHERE ciudad = Londres Cul es el peso total de todas las piezas suministradas por el proveedor S2? SELECT SUM (peso*cantidad)
(a)
(b)
(c)
(d)
FROM SPJ, P WHERE IdS = S2 AND SPJ.IdP = P.IdP Cul es el peso total de todas las piezas suministradas para proyectos de Madrid? SELECT SUM (peso*cantidad) FROM SPJ, P WHERE P.IdP = SPJ.IdP AND IdJ = (SELECT IdJ FROM J WHERE ciudad = Madrid)
Consultas agrupadas (clasula GROUP BY) Se utiliza para agrupar el resultado de la consulta por una determinada columna. Cul es el importe medio de todos los pedidos? SELECT AVG (importe) FROM pedidos Cul es el importe medio de cada vendedor? SELECT rep, AVG (importe) FROM pedidos GROUP BY rep sta consulta produce varias filas resumen, una fila por cada grupo resumiendo los pedidos realizados por cada uno de los vendedores. La clusula GROUP BY agrupa los datos de las tablas fuentes y produce una nica fila resumen por cada grupo de filas. Las columnas indicadas en la clusula GROUP BY se denominan columnas de agrupacin de la consulta y son las que determinan como se van a dividir las filas en grupos. Cul es el rango de cuotas asignadas en cada oficina? SELECT oficina_rep, MAX(cuota), MIN (cuota) FROM vendedores GROUP BY oficina_rep Si adems quisiramos obtenerlo ordenado por el nmero de oficina, habra que aadir despus de la lnea de GROUP BY, otra lnea que contuviese lo siguiente: ORDER BY oficina_rep Cuntos vendedores estn asignados a cada oficina? SELECT oficina_rep, COUNT (*) FROM vendedores GROUP BY oficina_rep Solucin: saldrn las oficinas de repuesto con el nmero de empleados que hay en cada oficina. Cuntos clientes diferentes son atendidos por cada vendedor? SELECT rep, COUNT (DISTINCT clie) FROM clientes GROUP BY rep Cuntos vendedores diferentes atienden a cada cliente? SELECT COUNT (DISTINCT clie), clientes son atendidos por el vendedor, rep FROM clientes
GROUP BY rep Recordemos que la funcin de columna coge una columna y produce un nico resultado, y cuando adems se tiene una clusula GROUP BY entonces se tienen que dividir los resultados detallados en grupos y aplicar la funcin de columna separadamente a cada grupo produciendo un nico resultado por cada grupo. Mltiples columnas de agrupacin: SQL puede agrupar resultados de consulta basndose en dos o ms columnas. Queremos agrupar todos los pedidos (suma de importes) por cada vendedor y por cada cliente. SELECT rep, clie, SUM (importe) FROM pedidos GROUP BY rep, clie En ste ejemplo la consulta produce una fila resumen separada para cada pareja vendedor cliente. Como ya hemos visto podemos usar la clusula GROUP BY conjuntamente con la clusula ORDER BY. Calcular los pedidos totales para cada cliente de cada vendedor, ordenados por cliente y dentro de cliente por vendedor. SELECT clie, rep, SUM (importe) FROM pedidos GROUP BY clie, rep ORDER BY clie, rep Las columnas de agrupacin tienen que ser columnas reales de las tablas de la clusula FROM y no pueden ser filas basndose en el valor de una expresin calculada. El tratamiento de los valores null lo veremos con nuestro SQL especfico (Transact SQL). Condiciones de bsqueda de grupo. Clusula HAVING Igual que WHERE se utiliza para seleccionar y rechazar filas individuales de una consulta, la clusula HAVING se utiliza para seleccionar y rechazar grupos de filas, siendo su formato HAVING <<condicin>>. Cul es el importe medio para cada vendedor cuyos pedidos totalizan ms de treinta mil dlares? SELECT rep, AVG (importe) FROM pedidos GROUP BY rep HAVING SUM (importe)>30000 sta consulta se efecta de la siguiente forma: GROUP BY reorganiza la tabla pedidos por grupos de vendedores. HAVING elimina los grupos donde el total de los pedidos no excede de treinta mil. SELECT calcula el importe medio para cada uno de los grupos restantes y genera los resultados de la consulta. Para cada oficina con dos o ms personas (vendedores), sacar su ciudad, la cuota total y las ventas totales de todos los vendedores que trabajan en la oficina. SELECT ciudad, SUM (cuota), SUM (vendedores.ventas) FROM vendedores, oficinas WHERE oficinas.oficina_rep = vendedores.oficina_rep GROUP BY ciudad HAVING COUNT (*)>1
Lo lgico sera haber puesto en la clusula GROUP BY oficina_rep, pero da un error, incluso si ponemos en la seleccin oficina_rep. Lo veremos con un ejemplo. Sacar la descripcin, el precio, las existencias y la cantidad total de los pedidos de cada uno de los productos, para los cuales la cantidad total pedida es superior al 75% de las existencias. Sacarlos ordenados de mayor a menor existencias. SELECT descripcin, precio, existencias, SUM (cant) FROM productos, pedidos WHERE id_fab = fab AND id_producto = producto GROUP BY id_fab, id_producto HAVING SUM (cant)>existencias*0.75 ORDER BY existencias DESC En teora estara bien, pero da un error. GROUP BY obliga a especificar descripcin, precio y existencias como columnas de agrupacin slo por el hecho de estar en la lista de seleccin y para que no d error. Realmente no contribuye en nada al proceso de agrupacin pues id_fab e id_producto especifican completamente una nica fila en la tabla productos haciendo automticamente que las otras tres columnas tengan un nico valor por grupo. Restricciones: la clusula HAVING se utiliza para incluir o excluir grupos de filas de los resultados de la consulta, por lo que la condicin de bsqueda tiene que ser aplicable al grupo en su totalidad en lugar de a filas individuales. Esto significa que un elemento que aparezca en la condicin de bsqueda de una clusula HAVING puede ser: Una constante. Una funcin de columna, que produzca un nico valor resumen de las filas del grupo. Una columna de agrupacin, que por definicin tiene el mismo valor para todas las filas del grupo. Una expresin que afecte a combinaciones de las anteriores. En la prctica la condicin de bsqueda en HAVING incluir al menos una funcin de columna, pues sino lo hiciera la condicin de bsqueda podra expresarse por la clusula WHERE y aplicarse a filas individuales. Para saber si una condicin de bsqueda pertenece a WHERE o a HAVING lo mejor es recordar como se aplican ambas clusulas: La clusula WHERE se aplica a filas individuales, por lo que las expresiones que contiene deben ser calculadas para filas individuales. La clusula HAVING se aplica a grupo de filas por lo que las expresiones que contengan deben ser calculables para un grupo de filas. Los valores nulos en HAVING producen tres resultados igual que con WHERE: Si la condicin de bsqueda es TRUE, ocurre que se coge el grupo de filas y contribuye con una fila resumen a los resultados de la consulta. Si es FALSE, el grupo de filas se descarta. Si es null, el grupo de filas tambin se descarta. Operador de existencia EXISTS El test de existencia EXISTS se asemeja a los tests ANY y ALL vistos anteriormente, lo que hace es comprobar si una subconsulta produce o no una fila de resultados. Su diagrama sintctico es el siguiente: <<NOT>> EXISTS subconsulta. Sacar aquellos productos y su descripcin para los cuales se ha recibido algn pedido con importe mayor o igual a $25000. Dicha consulta podramos haberla expresado de la forma: sacar aquellos productos para los cuales existe al menos un pedido en la tabla pedidos, que se refiera al producto en cuestin y que tiene un importe mayor o igual a $25000. SELECT descripcin FROM productos WHERE EXISTS (
a) b) c) d)
a) b)
c)
SELECT num_pedido
FROM pedidos WHERE producto = id_producto AND fab = id_fab AND importe >= $25000) SQL procesa sta consulta recorriendo la tabla productos y efectuando la subconsulta para cada producto. La subconsulta produce una columna que contiene los nmeros de pedidos de aquellos pedidos del producto actual que superan los $25000. Si hay alguno de dichos pedidos, es decir, si la columna de la subconsulta no est vaca el test EXISTS es true. Si la consulta no produce filas, el test EXISTS devuelve false. El test EXISTS no puede producir un valor nulo. En ocasiones tambin se utiliza la forma NOT EXISTS, simplemente hay que invertir la lgica del test EXISTS, es decir, es true si la subconsulta no produce filas, y false en caso contrario. Importante: la condicin de bsqueda EXISTS no utiliza realmente los resultados de la consulta, simplemente comprueba si la subconsulta produce algn resultado; por sta razn SQL suaviza la regla de que la subconsulta debe devolver una nica columna de datos, y permite utilizar la forma SELECT * en la subconsulta de un test EXISTS. El ejemplo anterior quedara de la siguiente forma: SELECT descripcin FROM productos WHERE EXISTS ( SELECT * FROM pedidos WHERE producto = id_producto AND fab = id_fab AND importe >= $25000) Listar las oficinas (cdigo de oficina y ciudad) en donde haya un vendedor cuya cuota represente ms del 60% del objetivo de la oficina. SELECT oficina, ciudad FROM oficinas WHERE EXISTS ( SELECT * FROM vendedores WHERE oficina_rep=oficina AND cuota>objetivo*0.6) Listar los clientes (nmero de cliente y nmero de la empresa) asignados al vendedor Sue Smith y que no han realizado un pedido superior a $3000. Observar que en los ejemplos la subconsulta incluye una referencia externa a una columna de la tabla de la columna principal. sta referencia externa lo que hace es enlazar la subconsulta a la fila que actualmente est siendo examinada que actualmente est siendo examinada. Subconsulta y composiciones Ya hemos visto que muchas de las consultas que hemos realizado se han escrito utilizando subconsultas, pero que tambin podran haber sido formuladas como consultas multitabla o composiciones. La realidad es que frecuentemente SQL permite escribir la consulta de cualquiera de las dos formas. Listar los nombres y edades de los vendedores que trabajan en oficinas de la regin Oeste. (Subconsulta) SELECT nombre, edad FROM vendedores WHERE oficina_rep IN (SELECT oficina FROM oficinas WHERE regin = Oeste) (Consulta multitabla = composicin) SELECT nombre, edad FROM vendedores, oficina WHERE oficina = oficina_rep AND regin = Oeste Cualquiera de las dos formas es correcta.
Sin embargo si modificamos la peticin para pedir lo siguiente: listar los nombres y edades de los vendedores que trabajan en oficinas de la regin Oeste y queremos adems las ciudades en donde ellos trabajan, entonces la forma de (Subconsulta) ya no funcionar y tendremos que utilizar la otra forma (Multitabla). Y al contrario, hay muchas consultas cuya solucin realizada con subconsultas no se pueden traducir a ninguna otra composicin equivalente. Sacar los nombres y edades de los vendedores que tienen cuota por encima de la cuota media de todos los vendedores. SELECT nombre, edad FROM vendedores WHERE cuota > (SELECT AVG (cuota) FROM vendedores) En ste caso la subconsulta interna es una consulta resumen. Subconsultas correlacionadas SQL efecta una subconsulta una y otra vez, una por cada fila de la consulta principal, y sin embargo hay muchas subconsultas que producen los mismos resultados para cada fila o grupo de filas. Sacar las ciudades de aquellas oficinas cuyas ventas estn por debajo del objetivo medio. SELECT ciudad FROM oficinas WHERE ventas < (SELECT AVG (objetivo) FROM oficinas) Cuantas oficinas hay? Cinco, por lo tanto la subconsulta se ejecuta cinco veces, y sin embargo el objetivo medio no cambia con cada oficina, que siempre es $550000. En estos casos SQL puede gestionar la consulta, primero efectuando la subconsulta en tabla temporal y luego usando dicha tabla en la consulta principal, algo parecido a lo siguiente: SELECT AVG (objetivo) AS b FROM oficinas SELECT ciudad FROM oficinas WHERE cuota > b Sin embargo esto no es posible si la subconsulta contiene una referencia externa, como ocurre en el siguiente ejemplo: sacar las ciudades de aquellas oficinas cuyos objetivos exceden a la suma de las cuotas de los vendedores que trabajan en ella. SELECT ciudad FROM oficinas WHERE objetivo > (SELECT SUM (cuota) FROM vendedores WHERE oficina_rep = oficina) En este caso SQL est obligado a realizar la subconsulta cinco veces, una por cada fila de la tabla oficinas. Para evitar posibles confusiones con los nombres de las columnas SQL siempre interpreta que se utiliza la tabla de la clusula FROM ms cercana al nombre de la columna en cuestin. Sacar los nombres de aquellos vendedores que tienen ms de 40 aos y dirigen a un vendedor por encima de la cuota. SELECT nombre FROM vendedores WHERE edad > 40 AND (SELECT director FROM vendedores
WHERE ventas > cuota) La columna director, ventas y cuota de la subconsulta son referencias a la tabla vendedores de la clusula FROM de la subconsulta, SQL no las interpreta como referencias externas y la subconsulta no es una subconsulta correlacionada. Si se quiere utilizar una referencia externa dentro de una subconsulta como la del ejemplo anterior, hay que utilizar una alias de la tabla para forzar la referencia externa. Listar los directores mayores de cuarenta aos y que dirigen a un vendedor cuyas ventas superan a la cuota y que no trabaja en la misma oficina que el director. SELECT nombre FROM vendedores AS v1 WHERE edad > 40 AND num_empl IN (SELECT director FROM vendedores AS v2 WHERE ventas > cuota AND v1.oficina_rep <> v2.oficina_rep)
Subconsultas en la clusula HAVING Tambin pueden utilizarse las subconsultas en la clusula HAVING de una consulta, funcionando como parte de la seleccin del grupo de filas efectuadas por la clusula HAVING. Listar los vendedores cuyo tamao de pedido medio para productos fabricados por la empresa ACI es superior a $30000. SELECT nombre, AVG (importe) FROM pedidos, vendedores WHERE fab = ACI AND rep = oficina_rep GROUP BY nombre HAVING AVG (importe) > 30000 Se agrupa por nombre para poder calcular el importe medio en la otra columna. Listar los vendedores cuyo tamao de pedido medio para productos fabricados por la empresa ACI es superior al tamao de pedido medio global. Los tamaos de pedido se refiere a los importes. Aclaracin: sacar el nombre del vendedor y su importe medio, agrupado por importe medio. SELECT nombre, AVG (importe) FROM vendedores, pedidos WHERE rep = oficina_rep AND fab = ACI GROUP BY nombre HAVING AVG (importe) > (SELECT AVG (importe) FROM pedidos) La clusula HAVING comprueba en cada grupo de filas si el tamao de pedido medio de ese grupo es superior al promedio de todos los pedidos cuyo dato se es calculado con antelacin, es decir, SQL puede calcular dicho promedio una vez y utilizarlo luego repetidamente en la clusula HAVING pues dicha subconsulta no contiene referencias externas. En la clusula HAVING tambin se puede utilizar una subconsulta correlacionadas. Sin embargo como la subconsulta se evala una vez por cada grupo de filas, todas las referencias externas de la subconsulta correlacionada deben tener un solo valor por cada grupo de filas, dicho de otra forma, la referencia externa tiene que ser una referencia a una columna de agrupacin de la consulta externa o bien estar contenida dentro de una funcin de columna. Listar los vendedores cuyo tamao de pedido medio para productos fabricados por la empresa ACI es superior al tamao de pedido medio global de ese vendedor.
SELECT nombre, AVG (importe) FROM vendedores, pedidos WHERE rep = oficina_rep AND fab = ACI GROUP BY nombre HAVING AVG (importe) > (SELECT AVG (importe) FROM pedidos WHERE rep = num_empl)
Alias de tablas Los alias de tablas se tienen que usar ciertas consultas como por ejemplo sacar los vendedores con cuota superior a la de sus directores (nombre, su cuota y la del director). SELECT vendedores.nombre, vendedores.cuota, dire.cuota FROM vendedores, vendedores dire WHERE vendedores.cuota > dire.cuota AND vendedores.director = dire.num_empl Sin embargo se puede pasar un alias de tabla en cualquier consulta simplemente porque el nombre de la tabla sea muy largo. Clusula FROM extendidas Tambin se podra haber titulado unin natural. Recordando el lgebra sabemos que la unin natural es una gran mejora sobre la multiplicacin de tablas pues produce un resultado ms ptimo (menos tuplas) y ms eficiente (menos tiempo de ejecucin). Sacar los nombres de aquellos proveedores que suministran la pieza P1. SELECT nombre FROM SPJ, S WHERE IdP = P1 AND S.IdS = SPJ.IdS Sacar los nombres de las piezas que se suministran en Agosto. SELECT DISTINCT nombre FROM P, SPJ WHERE P.IdP = SPJ.IdP AND mes = 8 Utilizando el producto cartesiano obtenemos la anterior consulta. Con la unin natural obtendramos: SELECT DISTINCT nombre FROM P JOIN SPJ ON P.IdP = SPJ.IdP WHERE mes = 8 Podramos hacer una mejora haciendo lo siguiente: SELECT FROM P JOIN (SELECT IdP FROM SPJ WHERE mes = 8) AS agosto ON P.IdP = agosto.IdP Realmente la clusula JOIN va ms all de la usada en lgebra, pues en la clusula OON se puede especificar la igualdad sino tambien >, <,... Aunque el estandar SQL no es obligatorio si se recomienda usar la clusula completa INNER JOIN. El estandar SQL incorpora la clusula NATURAL JOIN de forma que desaparece la clusula ON pues las tablas se unen por aquellas columnas con nombre idnticos y con igual valor. ste operados no est en nuestro Transact SQL. Veamos el diagrama sintctico completo del JOIN FROM tabla 1 (INNER / LEFT [OUTER], RIGHT [OUTER], FULL [OUTER], CROSS) JOIN tabla 2 ON condicin. Supongamos las siguientes tablas: A A1 A2 11 Z
9 A 3 B 4 X Null E 2 M B B1 B2 9 2.3 9 8.1 3 5.3 4 6.8 Null 7.8 2 5.5 10 Null 7 6.0 Resultado A1 A2 B1 B2 9 A 9 2.3 9 A 9 8.1 3 B 3 5.3 4 X 4 6.8 2 m 2 5.5 LEFT JOIN: aparecern todas las tuplas que cumplan la condicin ms todas las tuplas de la tabla primera y los otros valores se ponen a null. RIGHT JOIN: lo que hace es que aparezcan todas las tuplas que cumplan la condicin ms las tuplas de la tabla derecha. FULL JOIN: incluye todas las columnas de las dos tablas, las de LEFT y RIGTH. Cul es el peso total de todas las piezas suministradas por el proveedor S3? Primera forma: SELECT SUM (peso*cantidad) FROM P,SPJ WHERE P.IdP = SPJ.IdP AND IdS = S3 Segunda forma: SELECT SUM (peso*cantidad) FROM P INNER JOIN SPJ ON P.IdP = SPJ.IdP WHERE IdS = S3 SQL Server optimiza cualquier consulta que queramos realizar. SELECT IdP, SUM (peso*cantidad) AS Total de S3 FROM P INNER JOIN (SELECT * FROM SPJ WHERE IdS = S3) AS temporal ON P.IdP = temporal.IdP GROUP BY P.IdP Sacar la suma de los pesos de todas las piezas a proyectos de Granada. Vamos a hacerlo por partes con tablas intermedias. Paso 1: crear una tabla temporal con los proyectos de Granada. SELECT IdJ INTO JGRA FROM J WHERE ciudad = Granada Paso 2: crear una tabla temporal con las piezas suministradas a JGRA. SELECT IdP, cantidad INTO SUMIGRA FROM SPJ INNER JOIN JGRA ON SPJ.IdJ = JGRA.IdJ Paso 3: calcular el peso por la cantidad. SELECT SUM (peso*cantidad) FROM P INNER JOIN SUMIGRA ON p.IdP = SUMIGRA.IdP Paso 4: eliminar las tablas temporales.
DROP TABLE JGRA, SUMIGRA Sacar la suma de los pesos de todas las piezas a proyectos de Granada. SELECT SUM (peso*cantidad) FROM P INNER JOIN (SELECT IdP, cantidad FROM SPJ INNER JOIN (SELECT IdJ FROM J WHERE ciudad = Granada) AS JGRA ON SPJ.IdP = JGRA.IdJ) AS SUMIGRA La sentencia JOIN as como la creacin de tablas temporales es la que vamos a utilizar para la resolucin de las consultas de SQL. Se entiende que conceptualmente un JOIN es ms eficiente que un producto de tablas, aunque como observamos en SQL Server 2000 da igual. Se puede comprobar observando el plan de ejecucin. Clusula TOP n Para terminar el tema vamos a ver la clusula TOP n. TOP n especifica que slo se van a utilizar las n primeras filas del conjunto de resultados de la consulta. SELECT TOP 5 * FROM pedidos Lo que hace sta consulta es que saca las cinco primeras filas de la tabla. Sacar los cinco pedidos con mayor cantidad. SELECT TOP 5 IdS as prove., IdJ as proye., IdP as pieza, cantidad FROM SPJ ORDER BY cantidad DESC Con el TOP n tambien se utiliza la clusula WITH TIES. Lo que hace es sacar las n primeras filas y adems todas aquellas filas que sean iguales a la ltima. Sacar los cuatro pedidos con mayor cantidad. SELECT TOP 4 WITH TIES IdS, IdJ, IdP, cantidad FROM SPJ ORDER BY cantidad DESC Saca todos los alumnos con un apellido menor a Garca. SELECT * FROM alumnos WHERE apellido < Garcia ORDER BY apelido1 779 filas SELECT TOP 780 WITH TIES apellido1 FROM alumnos ORDER BY apellido1 831 filas Anotaciones finales Para terminar dos cuestiones: El alias de una columna es el nombre alternativo que se puede utilizar para reemplazar en la consulta el nombre de dicha columna. Es importante saber que no se puede usar en WHERE, ni en GROUP BY, ni en HAVING y si se puede utilizar en ORDER BY. SQL TRANSACT incorpora el operador unin. Sacar todos los apellidos diferentes considerando apellido1 y apellido2 diferentes en la tabla alumnos. SELECT apellido1 from alumnos UNION SELECT apellido2 from alumnos Se unen las dos consultas y saca todos los apellidos, y los que estn repetidos slo los saca una vez. Si quisiramos sacar tambin los repetidos SQL TRANSACT incorpora el operador UNION ALL