1.264 Tema 7 Introducción a SQL
Lenguaje de consulta estructurado (SQL) Tema 7: SELECT, INSERT, DELETE y UPDATE. Relaciones. Tema 8: Subconsultas. Vistas (tablas virtuales). Indexados. Transacciones. Seguridad. Rendimiento.
SQL El lenguaje de consulta estructurado (SQL) se utiliza para: La definición de datos: tablas y vistas (tablas virtuales). La recuperación de datos: por parte del usuario (consultas por un motivo concreto) o de un programa. La manipulación de datos: un usuario o programa puede añadir, borrar o modificar los datos. El control de acceso. La compartición de datos: por usuarios concurrentes. Mantener la integridad de los datos: mediante la definición de restricciones de integridad. No es un lenguaje completo como Java, Visual Basic o C++: SQL es un sublenguaje de unos 30 comandos. Por lo general, va insertado en otro lenguaje o herramienta para el acceso a bases de datos. SQL presenta varias incoherencias; los valores NULL causan problemas. Es transportable entre distintos sistemas operativos y, en cierto modo, también entre distribuidores.
Aspectos que varían entre las distintas implementaciones de SQL Los códigos de errores. Los tipos de datos que soportan (fecha/hora, moneda, variaciones de cadenas). Las tablas del sistema: sobre la estructura de la base de datos en sí. El SQL interactivo. La interfaz de programación: ningún distribuidor sigue el estándar. El SQL dinámico: utilizado por las herramientas de consulta y de redacción de informes. Algunas variaciones con respecto al estándar definidas por el fabricante. La inicialización, apertura y conexión de la base de datos.
Comandos básicos de SQL Tipos básicos: SELECT INSERT UPDATE DELETE SELECT es el más importante y complejo. Se utiliza para: Por separado, para recuperar datos (de formularios, informes, consultas y programas). Como parte de INSERT, para crear nuevas filas. Como parte de UPDATE, para actualizar filas. Como parte de DELETE, para eliminar filas.
La instrucción SELECT de SQL La instrucción SELECT está compuesta por varios comandos. Se utiliza para obtener columnas y/o filas de una o más tablas o vistas. Los comandos deben seguir un orden: SELECT columnas. FROM tabla o vista. INTO nueva tabla. WHERE se crea una relación o filas específicas. GROUP BY condiciones de agrupación (columnas). HAVING propiedades del grupo (filas específicas). ORDER BY criterios de ordenación.
Ejemplo de tablas Pedidos NumPedido Clien Prod Cant Importe Dto 1 211 Excavadora 7 31.000,00$ 0,2 2 522 Remachadora 2 4.000,00$ 0,3 3 522 Grúa 1 500.000,00$ 0,4 NumClien Empresa RepClien LimitCredit Clientes 211 Connor Co 89 50.000,00$ 522 AmaratungaEnterprise 89 40.000,00$ 890 Feni Fabricators 53 1.000.000,00$ RepVentas Oficinas NumRep Nombre OfiRep Cupo Ventas 53 Bill Smith 1 100.000,00$ 0,00$ 89 Jen Jones 2 50.000,00$ 130.000,00$ NumOfi Ciudad Estado Region Objetivo Ventas Telf 1 Denver CO West 3.000.000,00$ 130.000,00$ 970.586.3341 2 New York NY East 200.000,00$ 300.000,00$ 212.942.5574 57 Dallas TX West 0,00$ 0,00$ 214.781.5342
Ejemplo de esquema Pedidos NumPedido Prod Cant Importe NumClien (FK) (IE) Dto Clientes NumClien Empresa LimitCredit NumRep (FK) (IE) RepVentas NumRep Nombre Cupo Ventas NumRep (FK) (IE) Oficinas NumRep Ciudad Region Objetivo Ventas Estado Telf
Consultas SQL: SELECT Obtener un listado de los representantes de ventas: SELECT Nombre, Ventas, Cupo FROM RepVentas; Calcular la cantidad en la que cada representante supera o no llega al cupo: SELECT Nombre, Ventas, Cupo, (Ventas-Cupo) FROM RepVentas; Averiguar cuáles son los que menos trabajan: SELECT Nombre, Ventas, Cupo, (Ventas-Cupo) FROM RepVentas WHERE Ventas < Cupo; NumRep Nombre OfiRep Cupo Ventas 53 Bill Smith 1 100.000,00$ 0,00$ 89 Jen Jones 2 50.000,00$ 130.000,00$
Consultas SQL: calcular, insertar, eliminar y actualizar Calcular el promedio de ventas: SELECT AVG(Importe) FROM Pedidos; Calcular el promedio de ventas a un cliente: SELECT AVG(Importe) FROM Pedidos WHERE Clien = 211; Añadir una oficina: INSERT INTO Oficinas (NumOfi, Ciudad, Region, Objetivo, Ventas) VALUES ( 55, Dallas, West, 200000, 0); Eliminar un cliente: DELETE FROM Clientes WHERE Empresa = Connor Co ; Aumentar un límite de crédito: UPDATE Clientes SET LimitCredit = 75000 WHERE Empresa = Amaratunga Enterprises ;
SELECT: * y duplicados Seleccionar todas las columnas (campos): SELECT * FROM Oficinas; Filas duplicadas: la consulta mostrará dos entradas con "West": SELECT Region FROM Oficinas; Eliminar duplicados: SELECT DISTINCT Region FROM Oficinas; (El asistente de MS Access utiliza el comando no estándar DISTINCTROW, que es diferente de DISTINCT cuando hay relaciones).
NULL Los valores NULL evalúan a FALSO (NOT TRUE) en todos los casos: Insertar NuevoRep con Cupo NULL (en blanco o vacío). Las dos consultas siguientes no mostrarán todos los representantes de ventas: SELECT Nombre FROM RepVentas WHERE Ventas > Cupo; SELECT Nombre FROM RepVentas WHERE Ventas<= Cupo; Un nuevo representante con Cupo NULL no aparecerá en ninguna de las dos listas. Comprobar los NULLS: SELECT Nombre FROM RepVentas WHERE Cupo IS NULL;
Operadores SELECT SELECT * FROM <tabla> WHERE Dto*Importe > 50000; (Pedidos) WHERE Cupo BETWEEN 50000 AND 100000; (RepVentas) El rango es inclusivo (>=50000 y <=100000) WHERE Estado IN ( CO, UT, TX ); (Oficinas) WHERE NumRep IS NOT NULL; (RepVentas) WHERE Telf NOT LIKE 21% ; (Oficinas) El SQL estándar tiene sólo 2 comodines: % _ cualquier cadena de cero o más caracteres (* en Access). cualquier caracter individual (? en Access). La mayoría de las bases de datos tienen diferentes comodines adicionales. En MS Access:? (cualquier caracter individual), * (cualquier número de caracteres), # (cualquier dígito individual), [list] cualquier caracter individual de la lista, [!list]
SELECT: COUNT y GROUP BY Número de piezas del distribuidor A: SELECT COUNT(*) FROM Piezas WHERE Distribuidor = A ; Resultado: 4. Número de piezas de cada distribuidor: SELECT Distribuidor, COUNT(*) AS CuentaPiezas FROM Piezas GROUP BY Distribuidor; Resultado: Piezas PiezaID 123 A 234 A 345 B 362 A 2345 C 3464 A 4533 C Distribuidor Distribuidor CuentaPiezas A 4 B 1 C 2
Ejercicios Cuál es el límite medio de crédito de los clientes con un límite de crédito inferior a 1.000.000$? Cuántas oficinas de ventas hay en la región West? Aumentar un 30% el precio de las excavadoras en todos los pedidos. Eliminar cualquier representante de ventas con cupo NULL.
Soluciones Cuál es el límite medio de crédito de los clientes con un límite de crédito inferior a 1.000.000$? SELECT AVG(LimitCredit) FROM Clientes WHERE LimitCredit < 1000000; Cuántas oficinas de ventas hay en la región West? SELECT Count(*) FROM Oficinas WHERE Region= 'West ; Aumentar un 30% el precio de las excavadoras en todos los pedidos: UPDATE Pedidos SET Importe= Importe*1.3 WHERE Prod= 'Excavadora'; Eliminar cualquier representante de ventas con cupo NULL: DELETE FROM RepVentas WHERE Cupo IS NULL;
Relaciones El modelo relacional permite obtener datos de diferentes tablas para formar nuevas e imprevistas interrelaciones. Las interrelaciones se vuelven explícitas al manipular los datos: cuando se consulta la base de datos, no cuando se crea. Esto es muy importante; permite la extensibilidad de las bases de datos. La FAA nunca pensó que sus datos se utilizarían en el 1.264 junto con los del DOT, una tabla de códigos postales y algunas tablas de nuevos pedidos. Es reutilizar! Se puede relacionar cualquier columna de una tabla con cualquiera de otra mientras coincidan los tipos de datos y la operación tenga sentido. No es necesario que sean campos clave, aunque suelen serlo. Buenas relaciones: La columna relacionada suele ser un campo clave: ya sea clave primaria o secundaria. Las columnas relacionadas deben tener tipos de datos compatibles. Las de valor Null nunca se relacionan.
Relaciones Obtener un listado de todos los pedidos, en el que figuren el número de pedido y la cantidad y el nombre y límite de crédito del cliente: La tabla pedidos contiene el número de pedido y la cantidad, pero no los nombres ni los límites de crédito de los clientes. La tabla clientes contiene los nombres de los clientes y su límite de crédito, pero no la información de los pedidos. SELECT NumPedido, Importe, Empresa, LimitCredit FROM Clientes, Pedidos WHERE Clien = NumClien; (SQL estándar) SELECT NumPedido, Importe, Empresa, LimitCredit FROM Clientes INNER JOIN Pedidos ON Clientes.Númclien = Pedidos.Clien; (Access) NumPedido Clien Prod Cant Importe Dto 1 211 Bulldozer 7 31.000,00$ 0,2 2 522 Riveter 2 4.000,00$ 0,3 3 522 Crane 1 500.000,00$ 0,4 Relación NumClien Empresa RepClien LimitCredit 211 Connor Co 89 50.000,00$ 522 Amaratunga Enterprises 89 40.000,00$ 890 Feni Fabricators 53 1.000.000,00$
Relación entre 3 tablas Obtener un listado de los pedidos de más de 25.000 dólares, en el que figure el nombre del vendedor que atendió el pedido y el del cliente que lo realizó: SELECT NumPedido, Importe, Empresa, Nombre FROM Pedidos, Clientes, RepVentas WHERE Clien = NumClien AND RepClien = NumRep AND Importe >= 25000; (SQL estándar) NumPedido Clien Prod Cant Importe Dto 1 211 Excavadora 7 31.000,00$ 0,2 2 522 Remachadora 2 4.000,00$ 0,3 3 522 Grúa 1 500.000,00$ 0,4 NumClien Empresa RepClien LimitCredit 211 Connor Co 89 50.000,00$ 522 Amaratunga Enterprises 89 40.000,00$ 890 Feni Fabricators 53 1.000.000,00$ NumRep Nombre OfiRep Cupo Ventas 53 Bill Smith 1 100.000,00$ 0,00$ 89 Jen Jones 2 50.000,00$ 130.000,00$ Resultado: NumPedido Importe Empresa Nombre 1 34.000,00$ Connor Co Jen Jones 3 500.000,00$ AmaratungaEnterprise Jen Jones
Comentarios sobre las relaciones Sintaxis en MS Access del ejemplo anterior: SELECT NumPedido, Importe, Empresa, Nombre FROM RepVentas INNER JOIN (Clientes INNER JOIN Pedidos ON Clientes.NumClien = Pedidos.Clien) ON RepVentas.NumRep = Clientes.RepClien WHERE Importe >= 25000; Resulta un poco confuso; utilizaremos la herramienta consulta de MS Access para obtener el código SQL. Tener cuidado al utilizar * en las relaciones: Hace referencia a todas las columnas de todas las tablas implicadas en la relación. Si un campo tiene el mismo nombre en las tablas que se relacionan hay que cualificar su nombre: Utilizar tabla1.nombrecampo, tabla2.nombrecampo Clientes.NumClien, Pedidos.Importe, etc.
Relaciones dentro de la propia tabla NumEmp Nombre Posicion Enc 105 Mary Smith Analista 104 109 Jill Jones Analista senior 107 104 Sally Silver Encargado 111 107 Pat Brown Encargado 111 111 Eileen Howe Presidente Queremos un listado de los analistas y sus encargados: Encargado podría ser una clave secundaria de la tabla Encargados pero, en este caso, tiene que ser clave "secundaria" de la propia tabla Empleados. Intento 1: SELECT Nombre, Nombre FROM Empleados, Empleados WHERE Enc = NumEmp; (SQL estándar) Es errónea porque hace referencia a la tabla Empleados dos veces. Si eliminamos la segunda referencia tampoco sería correcta; esta consulta busca las filas en las que una persona es su propio encargado y eso no es lo que queremos.
Relaciones dentro de la propia tabla NumEmp Nombre Posicion Enc 105 Mary Smith Analista 104 109 Jill Jones Analista senior 107 104 Sally Silver Encargado 111 107 Pat Brown Encargado 111 111 Eileen Howe Presidente Intento 2: pretender que hay 2 copias de la tabla Empleados, una llamada Emp y la otra Enc: SELECT Emp.Nombre, Enc.Nombre FROM Emp, Enc WHERE Emp.Enc = Enc.NumEmp; (SQL estándar) SQL permite hacer esto mediante el uso de alias. Válido: SELECT Emp.Nombre, Enc.Nombre FROM Empleados Emp, Empleados Enc WHERE Emp.Enc = Enc.NumEmp; (SQL estándar) SELECT Emp.Nombre, Enc.Nombre FROM Empleados AS Emp INNER JOIN Empleados AS Enc ON Emp.Enc = Enc.NumEmp; (Access) En realidad sólo es necesario que utilicemos 1 alias (Enc).
Ejercicios Obtener un listado de los nombres de los clientes cuyo límite de crédito es superior al cupo de su representante de ventas. Listar también el límite de crédito y el cupo. Obtener un listado de los nombres y números de teléfono de los representantes.
Soluciones Obtener un listado de los nombres de los clientes cuyo límite de crédito es superior al cupo de su representante de ventas. Listar también el límite de crédito y el cupo: SELECT LimitCredit, Cupo, Empresa FROM RepVentas INNER JOIN Clientes ON RepVentas.NumRep = Clientes.RepClien WHERE LimitCredit > Cupo; Obtener un listado de los nombres y números de teléfono de los representantes: SELECT Nombre, Telf FROM Oficinas INNER JOIN RepVentas ON Oficinas.NumOfi = RepVentas.OfiRep;