Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 El lenguaje SQL El paso de la gestión automatizada de información basada en ficheros a la gestión basada en el uso de Sistemas Gestores de Bases de Datos (SGBDs) trajo consigo importantes cambios en el modo de diseñar, construir e utilizar aplicaciones informáticas. Uno de los cambios más significativos fue la aparición de los denominados lenguajes de consulta: muchos de los primeros SGBDs estaban acompañados de uno o más lenguajes desarrollados específicamente para el acceso a la información contenida en las BDs bajo su control. La idea es que esos lenguajes proporcionan una interfaz sencilla que simplifica el acceso a los datos, descargando buena parte de la responsabilidad (y la complejidad) del mismo sobre el propio SGBD. La auténtica diferencia de esos lenguajes con respecto a otros lenguajes de programación es su carácter declarativo: en lugar de especificar paso a paso las operaciones a realizar (la esencia de los lenguajes de programación imperativos), estos lenguajes permiten especificar únicamente el resultado deseado; dejando al SGBD la tarea de decidir la forma más adecuada de conseguir ese resultado. Esto convierte a los lenguajes de consulta de BDs en auténticos lenguajes de alto nivel; y los hace adecuados, por otro lado, para solucionar el problema de la dificultad de acceso a los datos: necesidades de información inesperadas y puntuales pueden ser resueltas de forma rápida y flexible. Uno de los primeros lenguajes de consulta de BDs fue el Structured Query Language (más conocido por sus siglas SQL), desarrollado por la compañía IBM para SYSTEM R, un SGBD relacional experimental. Con el paso del tiempo, SQL se ha convertido en un lenguaje estándar: prácticamente todos los SGBD relacionales del mercado lo soportan, en mayor o menor medida. De hecho, SQL cuenta ya con varias versiones, resultantes de sucesivas revisiones, datando la versión más reciente del año 1999 (de ahí esta sea conocida como SQL99) SQL es soportado por los SGBDs relacionales porque está fuertemente vinculado al modelo relacional: el SGBD da respuesta a cada consulta SQL por medio de la ejecución de una secuencia de operaciones del álgebra relacional (el álgebra – con los correspondientes operadores - que el modelo relacional incluye para permitir la manipulación de las relaciones). Los SGBDs suelen incluir entre las herramientas que los acompañan un intérprete de SQL: se trata de un programa informático capaz de recibir y evaluar consultas SQL, conectándose con la BD adecuada, y presentando al usuario los resultados obtenidos. Y los SGBDs también admiten que los programas de aplicación que necesiten acceder a una determinada BD le envíen sus solicitudes de información en forma de consultas SQL. Aunque hablemos de lenguajes de consulta, SQL es un lenguaje completo: no sólo permite recuperar información desde una BD, sino que también permite actualizar dicha información, e incluso definir la estructura de la propia BD. Podemos decir que SQL tiene dos vertientes: Lenguaje de Manipulación de Datos (LMD): SQL incluye instrucciones para el acceso y manipulación de la información contenida en una BD Autor: Juan Ramón López Rodríguez 1 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 - Instrucción SELECT: permite la recuperación de información Instrucción INSERT: permite introducir nuevos datos en la BD Instrucción UPDATE: permite la actualización de datos en la BD Instrucción DELETE: permite la eliminación de información de la BD Lenguaje de Definición de Datos (LDD): SQL permite también la definición y estructuración de las diferentes BDs controladas por un SGBD - Instrucción CREATE TABLE: crea una nueva relación en la BD. - Instrucción ALTER TABLE: permite la modificación de la estructura de una relación ya existente en la BD. - Instrucción DROP TABLE: permite la eliminación de una relación en la BD. Estas notas están destinadas a explicar únicamente la parte de SQL correspondiente a la instrucción SELECT. En caso de estar interesado en el resto de instrucciones, el lector o lectora puede acudir a la bibliografía citada en la última página, donde hayará excelentes explicaciones y ejemplos. Diferencias SQL – Modelo relacional Si bien SQL está fuertemente ligado al modelo relacional, no es menos cierto que presenta algunas diferencias importantes en cuanto al manejo de los datos: - - - Una primera diferencia es terminológica: donde el modelo relacional habla de relaciones, tuplas, y atributos, SQL habla de tablas, filas y columnas. Nosotros no haremos distinciones y manejaremos indistintamente ambas terminologías. El modelo relacional no admite la existencia de tuplas repetidas en una relación (restricción de clave). En cambio, SQL admite sin problemas la existencia de filas repetidas en una tabla (veremos más adelante por qué). Lo que en el modelo relacional son dominios (conjunto de valores válidos para un atributo), en SQL son tipos de datos. Los tipos de datos definen los valores posibles para un atributo, pero también las operaciones que pueden ser realizadas con esos valores (suma, resta, multiplicación, división, concatenación....) . Los tipos de datos más frecuentes en SQL son: Tipo de datos SQL NUMBER (numDigitos) CHAR(numCaracteres) DATETIME Nombre que recibe en Access Númerico TEXTO (numCaracteres) Fecha/Hora Operaciones soportadas +,-,*,/ + (concatenación) Ejemplo 53 ‘Casa’ 03/09/57 Ejemplo a utilizar Antes de abordar la descripción de la instrucción SELECT de SQL, estableceremos el ejemplo de partida que utilizaremos a lo largo de la explicación. Se trata del esquema lógico - relativo a la gestión de una empresa – que habíamos obtenido al analizar la transformación desde el modelo ER al modelo relacional. Autor: Juan Ramón López Rodríguez 2 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais Empleado (NSS, NPila, Ap1, Ap2, Sexo, Dirección, FNac, NumDept, NSSSupervisor) Departamento (NumDept, NomDept, NSS, FechaIniGerente) TrabajaEn (NSS, Numero, Horas) LocalidadDpt (NumDept, Loc) Proyecto (Numero, Nombre, Loc, NumDept) Las relaciones, desde el punto de vista de SQL, deben ser consideradas como tablas; asumiremos que, como tales, contienen los siguientes datos en un momento dado: NSS NPila 1 Juan 2 Pedro 3 María 4 Antonio Empleado Ap1 Ap2 Sexo Dirección Pérez Pérez H R/ Vilar 2 López Blas H R/ Fontes 12 Pérez Pi M R/ Galicia 6 Botín Castro H Pza Galicia 1 FNac NumDept NSSSupervisor 02/06/64 D01 23/12/50 D01 1 12/03/75 D02 13/01/65 D02 3 Departamento NumDept NomDept NSS FechaIniGerente D01 Ventas 1 01/01/2000 D02 Produccion 2 01/01/2004 Proyecto Numero Nombre Localidad NumDept V1 Sistema contable A Coruña D01 P1 Producto A Ferrol D02 P2 Producto B Ferrol D02 TrabajaEn NSS Numero Horas 1 V1 10 2 V1 35 3 P1 20 4 P1 5 4 P2 30 LocalidadDpt NumDept Loc D01 A Coruña D02 A Coruña D02 Ferrol La instrucción SELECT La instrucción SELECT de SQL se utiliza para recuperar (realizando un procesamiento previo, si fuese necesario) información de la BD. Se trata de una instrucción que toma como parámetros de entrada una o mas tablas, y devuelve como resultado una nueva tabla, generada dinámicamente, que contiene la información solicitada. El resultado puede ser desde una tabla con una única fila y una única columna (es decir, un único valor) hasta una tabla con múltiples filas y columnas. Autor: Juan Ramón López Rodríguez 3 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 La instrucción SELECT está formada por un conjunto de cláusulas, que ayudan a precisar la información que se solicita. La sintaxis general de una instrucción SELECT es la siguiente SELECT [distinct] <lista de expresiones> FROM <lista de tablas> WHERE <condiciones de selección> ORDER BY <lista expresiones ordenación> - cláusula select cláusula from cláusula where cláusula order by La cláusula FROM permite especificar la tabla o tablas de la base de datos desde donde se va a recuperar la información que se necesita. La cláusula WHERE permite especificar un conjunto de condiciones para la selección de los datos que se recuperarán de las tablas para elaborar el resultado. La cláusula SELECT permite especificar la información a recuperar exactamente, y, de ser necesario, el procesamiento que debe ser realizado sobre esos datos. Finalmente, la cláusula ORDER BY permite especificar el orden en el que va a ser presentada la información en la tabla resultante. En realidad, no todas estas cláusulas deben aparecer obligatorias en una consulta Select. Sólo lás cláusulas SELECT y FROM son imprescindibles para formar una consulta Select mínima. La cláusula SELECT Supongamos que queremos recuperar el NSS y el nombre completo (nombre de pila + apellidos) de todos los empleados de la empresa. Una consulta que lo permite sería la siguiente: Select NSS, NPila, Ap1, Ap2 FROM Empleado ...y el resultado de evaluar la consulta sería el siguiente: NSS NPila 1 Juan 2 Pedro 3 María 4 Antonio Ap1 Ap2 Pérez Pérez López Blas Pérez Pi Botín Castro ¿Cómo se obtiene esta tabla? Una consulta Select se evalúa de la siguente manera: 1) En primer lugar, se evalúa la cláusula FROM: es necesario determinar de qué tabla vamos a recuperar la información: por ejemplo, Empleado. 2) A continuación, se accede a la tabla indicada, y se recuperan, una a una, todas sus filas, sobre las que será evaluada, una por una, la cláusula SELECT: cada fila de la tabla original (Empleado) va a dar lugar a una nueva fila en la tabla que contendrá el resultado de la consulta. 3) La cláusula SELECT debe contener una lista de una o más expresiones, separadas Autor: Juan Ramón López Rodríguez 4 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 por comas. - Cada una de esas expresiones será evaluada sobre cada fila de la tabla original, dando lugar a una lista de valores atómicos (tantos como expresiones) - La lista obtenida servirá para crear una nueva fila en la tabla resultado. - La tabla resultado tendrá una columna por cada expresión incluida en la cláusula SELECT - El nombre de cada columna será igual a la expresión que la genera. 4) Serán expresiones válidas (expresiones que pueden ser utilizadas en la cláusula SELECT): - Un valor constante, de cualquiera de los tipos de datos admitidos en SQL: por ejemplo ‘Juan’, 5, 03/02/2004. El resultado de evaluar un valor constante sobre una fila coincide siempre con el propio valor constante. - Un nombre de columna de aquellos incluidos en la tabla indicada en el FROM: por ejemplo, NSS, NPila, Ap1 o Ap2. Al evaluar un nombre de columna sobre una fila determinada, el resultado será el valor de la fila en esa columna. - Una expresión que incluya operaciones realizadas sobre valores constantes y/o nombres de columnas. El resultado de la expresión será el mismo que el resultado de evaluar primero los valores constantes y los nombres de columnas, y operarlos después. Por ejemplo: 2 (Resultado: 2) 2+3 (Resultado: 5) ‘Fede’ + ‘rico’ (Resultado: ‘Federico’) Ap1 + Ap2 (Resultado: dada una fila de la tabla original, la concatenación de los valores de sus columnas Ap1 y Ap2) ‘Nombre:’ + NPila (Resultado: dada una fila de la tabla original, la concatenación de la cadena ‘Nombre:’ y el valor de la fila en la columna NPila) En el caso de nuestro ejemplo, la evaluación de la consulta se realiza como sigue: - - En primer lugar, se utiliza la cláusula FROM para determinar la tabla de origen de los datos: Empleado, que es la tabla que contiene toda la información que necesitamos. A continuación, se analiza una por una cada fila de Empleado: Para la primera fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 1 Juan Pérez Pérez H R/ Vilar 2 02/06/64 D01 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 1 NPila: ‘Juan’ Ap1: ‘Pérez’ Ap2: ‘Pérez’ ...y por lo tanto, la fila que se genera en la tabla resultado es: 1 Juan Pérez Pérez Autor: Juan Ramón López Rodríguez 5 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 Para la segunda fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 2 Pedro López Blas H R/ Fontes 12 23/12/50 D01 1 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 2 NPila: ‘Pedro’ Ap1: ‘López’ Ap2: ‘Blas’ ...y por lo tanto, la fila que se añade a la tabla resultado es: 2 Pedro López Blas Para la tercera fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 3 María Pérez Pi M R/ Galicia 6 12/03/75 D02 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 3 NPila: ‘María’ Ap1: ‘Pérez’ Ap2: ‘Pi’ ...y por lo tanto, la fila que se añade a la tabla resultado es: 3 María Pérez Pi Finalmente, para la cuarta y última fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 4 Antonio Botín Castro H Pza Galicia 1 13/01/65 D02 3 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 4 NPila: ‘Antonio’ Ap1: ‘Botín’ Ap2: ‘Castro’ ...y por lo tanto, la fila que se añade a la tabla resultado es: 4 Antonio Botín Castro - Como último paso, las filas obtenidas se unen para obtener la tabla resultante: NSS NPila 1 Juan 2 Pedro 3 María 4 Antonio - Ap1 Ap2 Pérez Pérez López Blas Pérez Pi Botín Castro Como se puede apreciar, las columnas tienen por nombre la expresión (incluida en la cláusula SELECT) que da lugar a sus valores La consulta que hemos visto utiliza expresiones en la cláusula SELECT que están constituidas por simples nombres de columnas. Sin embargo, podemos realizar consultas más sofisticadas incluyendo expresiones más complejas. Por ejemplo, podemos modificar la consulta anterior para que el nombre completo de cada empleado aparezca en una única columna: Autor: Juan Ramón López Rodríguez 6 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 Select NSS, Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila FROM Empleado En esta nueva consulta, reemplazamos las tres expresiones que se referían a las columnas de nombre y apellidos de los empleados por una expresión única, en la que se utiliza el operador de concatenación de cadenas (+) para unir los valores de dichas columnas, separados por espacios y comas: se trata de una expresión en la que se combinan nombres de atributos y valores constantes (‘ ‘ y ‘,’ ). La consulta se evaluará de la siguiente forma: Para la primera fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 1 Juan Pérez Pérez H R/ Vilar 2 02/06/64 D01 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 1 Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila = ‘Pérez’ + ‘ ‘ + ‘Pérez’ + ‘, ‘ + ‘Juan’ = ‘Pérez Pérez, Juan’ ...y por lo tanto, la fila que se genera en la tabla resultado es: 1 Pérez Pérez, Juan Para la segunda fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 2 Pedro López Blas H R/ Fontes 12 23/12/50 D01 1 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 2 Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila = ‘López’ + ‘ ‘ + ‘Blas’ + ‘, ‘ + ‘Pedro’ = ‘López Blas, Pedro’ ...y por lo tanto, la fila que se añade a la tabla resultado es: 2 López Blas, Pedro Para la tercera fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 3 María Pérez Pi M R/ Galicia 6 12/03/75 D02 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 3 Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila = ‘Pérez’ + ‘ ‘ + ‘Pi’ + ‘, ‘ + ‘María’ = ‘Pérez Pi, María’ ...y por lo tanto, la fila que se añade a la tabla resultado es: 3 Pérez Pi, María Finalmente, para la cuarta y última fila... NSS NPila Ap1 Ap2 Sexo Dirección FNac NumDept NSSSupervisor 4 Antonio Botín Castro H Pza Galicia 1 13/01/65 D02 3 ...las expresiones de la cláusula SELECT se evalúan así: NSS: 4 Autor: Juan Ramón López Rodríguez 7 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila = ‘Botín’ + ‘ ‘ + ‘Castro’ + ‘, ‘ + ‘Antonio’ = ‘Botín Castro, Antonio’ ...y por lo tanto, la fila que se añade a la tabla resultado es: 4 Botín Castro, Antonio - Como último paso, las filas obtenidas se unen para obtener la tabla resultante: NSS Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila 1 Pérez Pérez, Juan 2 López Blas, Pedro 3 Pérez Pi, María 4 Botín Castro, Antonio Las expresiones complejas no tienen por que utilizar sólo atributos o valores de tipo carácter. La siguiente consulta devuelve el número mensual de horas que cada empleado le dedica a cada proyecto (que se obtienen multiplicando por 4 el número de horas semanal por proyecto, almacenado en la tabla TrabajaEn): Select NSS, Numero, Horas* 4 FROM TrabajaEn Es fácil comprobar que el resultado de esta consulta sería la siguiente tabla: TrabajaEn NSS Numero Horas*4 1 V1 40 2 V1 140 3 P1 80 4 P1 20 4 P2 120 Con este ejemplo demostramos algo que habíamos afirmado anteriormente: la instrucción Select de SQL permite no sólo recuperar información almacenada en una BD, sino también procesar dicha información para generar información nueva. Valores nulos El modelo relacional admite el uso de los valores nulos durante la asignación de valores a los atributos de una tupla. Eso significa, en la terminología de SQL, que podemos encontrarnos con celdas de una tabla que alberguen valores nulos. Por lo tanto, la cláusula SELECT puede involucrar, en sus expresiones, valores nulos (al evaluar esas expresiones sobre los valores de una fila determinada). La pregunta es ¿cómo afectan los valores nulos al cálculo de expresiones incluidas en una cláusula SELECT? Y la respuesta es sencilla: el valor de un nulo es desconocido; por lo tanto, en toda expresión en la que intervenga un valor nulo, el resultado será también desconocido.1 Y en la tabla resultante, el valor desconocido se representará mediante otro valor nulo. - 1 2 + Nulo = Nulo ‘Casa’ + Nulo = Nulo NSS – 5 = Nulo (si NSS se evalúa a Nulo) Ya que, si nos falta alguno de los parámetros de la expresión, es imposible determinar el resultado. Autor: Juan Ramón López Rodríguez 8 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 Ejemplo: Indica el NSS de cada empleado y el de su jefe. Select NSS, NSSSupervisor FROM Empleado La consulta se evalúa de la siguiente forma: NSS Npila 1 Juan 2 Pedro 3 María 4 Antonio Empleado Ap1 Ap2 … Pérez Pérez ... López Blas ... Pérez Pi ... Botín Castro ... NSSSupervisor 1 3 … ... ... ... ... NSS 1 2 3 4 NSSSupervisor (Nulo) 1 (Nulo) 3 NSS 1 2 3 4 NSSSupervisor 1 3 Filas repetidas: el modificador distinct Supongamos que necesitamos conocer las diferentes localidades en las que nuestra empresa dispone de alguna sede. En la base de datos contamos con información referente a las sedes de los departamentos de la empresa (concretamente, en la tabla LocalidadDpt); y conociendo las sedes de los departamentos, conoceremos las de la empresa (ya que, en buena lógica, deben coincidir). Por lo tanto, la siguiente consulta debería servir a nuestros fines: SELECT Loc FROM LocalidadDpt Como en los casos anteriores, la consulta se evalúa recuperando una por una las filas de la tabla indicada y evaluando las expresiones de la cláusula SELECT sobre cada una de ellas: LocalidadDpt NumDept Loc D01 A Coruña D02 A Coruña D02 Ferrol Evaluación de ‘Loc’: A Coruña A Coruña Ferrol El resultado de la consulta sería este: Loc A Coruña A Coruña Ferrol Como se puede apreciar, una de las localidades aparece repetida: se trata de A Coruña, como resultado de ser obtenida como sede de dos departamentos diferentes. Esto es así porque SQL incumple la restricción de clave del modelo relacional, que exige que en una relación (una tabla) no puede haber filas repetidas. Así, al verse liberado de la obligación de comprobar esta restricción, cualquier intérprete de SQL podrá procesar una consulta mucho más rápidamente. Sin embargo, SQL sí que permite eliminar filas repetidas en el resultado de una consulta (aunque provocando, probablemente, un retraso adicional por parte del intérprete en la Autor: Juan Ramón López Rodríguez 9 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 obtención del resultado final). Para hacerlo, la cláusula SELECT cuenta con el modificador distinct: añadiendo este modificador a nuestra consulta... SELECT distinct Loc FROM LocalidadDpt ...el resultado de la misma pasaría a ser este: Loc A Coruña Ferrol ...de forma que obtendríamos ya los datos en la forma deseada. Es importante resaltar que distinct permite eliminar filas repetidas, y no valores repetidos. Por ejemplo, estas dos consultas (que nos devuelven una lista con los nombres de los empleados y el departamento en el que trabajan): SELECT NumDept, Npila FROM Empleado SELECT distinct NumDept, Npila FROM Empleado …devolverán como resultado la misma tabla: NumDept NPila D01 Juan D01 Pedro D02 María D02 Antonio Si bien en la columna NumDept hay varios valores repetidos, no hay ninguna fila repetida; por lo tanto, la presencia o no de distinct en la consulta no afecta al resultado final. Versión abreviada del SELECT Es bastante usual encontrarse en la necesidad de recuperar toda la información contenida en una tabla. Hacerlo por medio de una consulta SQL implicaría escribir uno por uno todos los nombres de sus columnas en la cláusula SELECT: SELECT NSS, Npila, Ap1, Ap2, Sexo, Direccion, Fnac, NumDept, NSSSupervisor FROM Empleado Para evitar esto, la cláusula SELECT admite un carácter comodín, que representa a todas las columnas de una tabla: el asterisco (*). Así, la siguiente consulta sería equivalente a la anterior: SELECT * FROM Empleado Ordenación del resultado: la cláusula ORDER BY. En los ejemplos anteriores estamos asumiendo que el orden de presentación de los resultados de una consulta se basa en el orden inicial de las filas de la tabla de partida. Autor: Juan Ramón López Rodríguez 10 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 En realidad, nada nos garantiza ese orden: la definición formal de SQL no nos indica nada a ese respecto. Además, la definición del modelo relacional (que, no lo olvidemos, es la base de SQL) especifica que una relación (una tabla) es un conjunto de tuplas: tratándose de un conjunto, el concepto de orden no es aplicable. ¿A dónde nos lleva todo esto? Si ejecutamos dos veces una misma consulta, nada nos garantiza que los resultados aparezcan en el mismo orden las dos veces. En realidad, se trata de un problema que tiene fácil solución: SQL incorpora, en la instrucción SELECT, una cláusula – ORDER BY – que nos permite especificar el orden deseado de presentación de los resultados. El orden se establece a través de una o más expresiones de ordenación, que se incluyen en la cláusula ORDER BY separadas por comas: - - - Para cada fila de la tabla original se calculan los valores de esas expresiones. Las filas originales se ordenan de acuerdo a los valores resultantes de evaluar las expresiones de ordenación: en primer lugar se tienen en cuenta los resultados de la primera expresión; se toman después en cuenta los resultados de la segunda; y así sucesivamente. Los valores resultantes de cada expresión pueden ser ordenados de forma ascendente o descendente: para ello se utilizan los modificadores ASC (la opción por defecto) y DESC. Las filas del resultado se ordenan en función del orden establecido para las filas de la tabla original a partir de las que son obtenidas. Veremos a continuación dos ejemplos del uso de la cláusula ORDER BY para precisar mejor su funcionamiento. Ejemplo: Obtener la lista de empleados de la empresa, ordenados alfabéticamente por sus apellidos. SELECT NSS, Ap1+ ‘ ‘ + Ap2 + ‘,’ + Npila FROM Empleado ORDER BY Ap1, Ap2, Nombre Esta consulta se evalúa de la siguiente forma: - Para cada fila de la tabla Empleado se evalúan las expresiones de ordenación: Empleado NSS NPila Ap1 Ap2 1 Juan Pérez Pérez 2 Pedro López Blas 3 María Pérez Pi 4 Antonio Botín Castro - … ... ... ... ... Ap1 Ap2 NPila Pérez Pérez Juan López Blas Pedro Pérez Pi María Botín Castro Antonio Las filas se ordenan empleando la primera expresión (Ap1), de forma ascendente (la opción por defecto): Empleado NSS NPila Ap1 Ap2 … 4 Antonio Botín Castro ... 2 Pedro López Blas ... Autor: Juan Ramón López Rodríguez Ap1 Ap2 NPila Botín Castro Antonio López Blas Pedro 11 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais 3 1 - María Juan Pérez Pi Pérez Pérez ... ... María Juan Como se puede observar, dos filas (las correspondientes a María y Pedro) presentan en mismo valor para Ap1. Para decidir su orden, recurrimos a la segunda expresión (Ap2) Empleado NSS NPila Ap1 Ap2 4 Antonio Botín Castro 2 Pedro López Blas 1 Juan Pérez Pérez 3 María Pérez Pi - Pérez Pi Pérez Pérez … ... ... ... ... Ap1 Ap2 NPila Botín Castro Antonio López Blas Pedro Pérez Pérez Juan Pérez Pi María Ya no es necesario recurrir a la última expresión (NPila) para resolver el orden final. Conocido el orden, llega el momento de evaluar la cláusula SELECT y resolver la consulta, respetando el orden previamente establecido. Empleado NSS NPila Ap1 Ap2 4 Antonio Botín Castro 2 Pedro López Blas 1 Juan Pérez Pérez 3 María Pérez Pi … ... ... ... ... NSS 4 2 1 3 Ap1+ ‘ ‘ + Ap2 + ‘,’ + Npila Botín Castro, Antonio López Blas, Pedro Pérez Pérez, Juan Pérez Pi, María Ejemplo: Indicar los NSS de todos los empleados de la empresa, ordenados por departamento y por edad (los más jóvenes primero). Ordenar por edad, de forma ascendente, implica ordenar por fecha de nacimiento (el dato que poseemos sobre los empleados) de forma descendente. Por lo tanto, la consulta a realizar sería esta: SELECT NSS, NumDept FROM Empleado ORDER BY NumDept, Fnac DESC Obsérvese el uso que se hace del modificador DESC para exigir que las filas se ordenen por fecha de forma descendente (de mayor a menor, en lugar de de menor a mayor) El resultado de la consulta sería el siguiente: Empleado NSS Npila Ap1 1 Juan Pérez 2 Pedro López 3 María Pérez 4 Antonio Botín Ap2 Pérez Blas Pi Castro … ... ... ... ... NumDept D01 D01 D02 D02 FNac 02/06/64 23/12/50 12/03/75 13/01/65 NSS NumDept 1 D01 2 D01 3 D02 4 D02 (Se da la casualidad en el ejemplo que el orden solicitado en origen para las tuplas es aquel en el que las habíamos presentado inicialmente). Filtrado de información: la cláusula WHERE La cláusula WHERE permite afinar en mayor medida la recuperación de información mediante una instrucción SELECT. Hasta ahora hemos visto cómo seleccionar cuáles de Autor: Juan Ramón López Rodríguez 12 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais las columnas de una tabla nos interesan; mediante WHERE podremos seleccionar cuáles de las filas contenidas en una tabla nos interesan. Eso nos permitirá, por ejemplo, restringir cualquiera de las consultas que hemos realizado hasta ahora a los empleados de un determinado departamento. Así, la consulta siguiente permitirá obtener el nombre de todos los empleados del departamento de Ventas. Select NSS, Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila FROM Empleado WHERE NumDept=’D01’ Para seleccionar las filas que nos interesen, la cláusula WHERE va acompañada de un conjunto de condiciones de selección. Sólo las filas que cumplan esas condiciones serán tenidas en cuenta para evaluar la consulta. Condiciones simples La condición de selección más sencilla que se puede definir es aquella que obliga a comparar los valores de dos expresiones evaluadas sobre cada fila de la tabla. Expresión1 = > < <> >= <= Expresión 2 La idea es que tanto Expresión1 como Expresión2 se evalúen sobre los valores de cada fila de la tabla original. Una vez evaluados, se comparan. Si la condición especificada se cumple, la fila se selecciona. Si la condición no se cumple, la fila es descartada. En el caso del ejemplo de la consulta anterior (datos de los empleados del departamento de Ventas, D01), la evaluación se haría así: - En primer lugar, seleccionar las filas a utilizar para calcular el resultado, aplicando la condición de selección del WHERE NSS Npila 1 Juan 2 Pedro 3 María 4 Antonio - Empleado Ap1 Ap2 Pérez Pérez López Blas Pérez Pi Botín Castro … NumDept … ... D01 ... ... D01 ... ... D02 ... ... D02 ... NumDept D01 D01 D02 D02 ‘D01’ D01 D01 D01 D01 NumDept=’D01’ Verdadero Verdadero Falso Falso Fila seleccionada Una vez seleccionadas las filas, se procede de la forma acostumbrada: Empleado NSS Npila Ap1 Ap2 … NumDept … 1 Juan Pérez Pérez ... D01 ... 2 Pedro López Blas ... D01 ... Autor: Juan Ramón López Rodríguez NSS Ap1 + ‘ ‘ + Ap2 + ‘, ‘ + NPila 1 Pérez Pérez, Juan 2 López Blas, Pedro 13 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais Otro ejemplo podría ser este: Nombres de todos los empleados de la empresa que hayan nacido antes que Pedro. La consulta que nos permite obtener esa información es esta: Select NPila FROM Empleado WHERE Fnac<23/12/50 Y se evaluará de la siguiente forma: NSS Npila 1 Juan 2 Pedro 3 María 4 Antonio Empleado Ap1 Ap2 Pérez Pérez López Blas Pérez Pi Botín Castro … NumDept … ... D01 ... ... D01 ... ... D02 ... ... D02 ... Fnac 02/06/64 23/12/50 12/03/75 13/01/65 23/12/50 23/12/50 23/12/50 23/12/50 23/12/50 Fnac < 23/12/50 Falso Falso Falso Falso Fila seleccionada Como se puede apreciar, ninguna fila de la tabla satisface la condición, por lo que el resultado de la consulta será una tabla vacía: ¡Pedro es el empleado más viejo de la empresa! NPila Valores nulos: el predicado IS NULL Los valores nulos también afectan a la evaluación de las condiciones de selección. La evaluación de cualquier condición de selección en la que intervenga una expresión con evaluación desconocida, será también desconocida. - - ¿ 2 > Nulo ? Desconocido ¿ ‘Casa’ <> Nulo ? Desconocido ¿ NSS = 5 ? Desconocido (si NSS se evalúa a Nulo) Siempre que no sea posible determinar si una condición se verifica para una determinada fila, adoptaremos una postura conservadora: al ser desconocido el resultado de la comparación, descartaremos la fila al calcular el resultado de la condición, por si en un momento dado, y con más información, llegásemos a determinar que la condición no se cumple. Ejemplo: Recuperar el NSS de todos los empleados de la empresa que cuentan con un supervisor. La consulta que nos permite obtener esta información es la siguiente: Select NSS FROM Empleado WHERE NSSSupervisor > 0 …y se evalúa de la siguiente forma: Autor: Juan Ramón López Rodríguez 14 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais NSS Npila 1 2 3 4 Juan Pedro María Antonio Empleado Ap1 Ap2 … NSSSupervisor … Pérez Pérez López Blas Pérez Pi Botín Castro ... ... ... ... 1 3 ... ... ... ... NSS NSSSupervisor 1 2 3 4 (Nulo) 1 (Nulo) 3 ¿ NSSSupervisor >0? Desconocido Verdadero Desconocido Verdadero Fila seleccionada Como se puede apreciar, dos filas – correspondientes a dos empleados de la empresa – presentan un valor nulo en la columna NSSSupervisor. En esos dos casos, la condición ¿NSSSupervisor > 0 ? no puede ser evaluada, y las dos filas se descartan. Es decir, estamos descartando las filas correspondientes a empleados sin supervisor; que es precisamente lo que pretendíamos hacer. La consulta se termina de evaluar de la siguiente forma: NSS Npila 2 Pedro 4 Antonio Empleado Ap1 Ap2 … López Blas ... Botín Castro ... NSSSupervisor 1 3 … ... ... NSS 2 4 NSS 2 4 El siguiente ejemplo resulta más complicado de resolver: Ejemplo: Recuperar el NSS de todos los empleados de la empresa que no tienen supervisor. Se trata de seleccionar aquellas filas (empleados) con valor nulo en la columna NSSSupervisor. El problema es el siguiente: cualquier comparación con un valor nulo hará que una fila sea descartada, precisamente lo contrario de lo que deseamos en este caso. Por ejemplo, es fácil ver cómo la siguiente consulta... Select NSS FROM Empleado WHERE NSSSupervisor = NULL … devolvería como resultado una tabla vacía, por la propia semántica definida para la cláusula WHERE: el operador de comparación = se evalúa a nulo si hay un nulo de por medio, y en este caso todas las filas de la tabla original serían descartadas (en todas las comparaciones intervendrá el valor NULL). Para resolver este contratiempo, SQL permite una alternativa en forma de predicado lógico2: IS NULL. Este predicado (asociado a un nombre de columna) nos permitirá saber si el valor de dicha columna para una fila es nulo o no. - Si el valor de la columna es nulo, IS NULL se evaluará como Verdadero Si el valor de la columna no es nulo, IS NULL se evaluará como Falso Utilizando IS NULL en nuestro ejemplo, la consulta se resuelve así: 2 Podemos entender un predicado como una función que devuelve como resultado un valor lógico de Verdadero o Falso Autor: Juan Ramón López Rodríguez 15 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais Select NSS FROM Empleado WHERE NSSSupervisor IS NULL Y se evalúa de esta manera: NSS Npila 1 2 3 4 Juan Pedro María Antonio Empleado Ap1 Ap2 … NSSSupervisor … Pérez Pérez López Blas Pérez Pi Botín Castro ... ... ... ... 1 3 ... ... ... ... NSS NSSSupervisor 1 2 3 4 (Nulo) 1 (Nulo) 3 ¿ NSSSupervisor IS NULL ? Verdadero Falso Verdadero Falso Fila seleccionada ...siendo este el resultado final: Empleado NSS Npila Ap1 Ap2 … NSSSupervisor … 1 Juan Pérez Pérez ... ... 3 María Pérez Pi ... ... NSS 1 3 El predicado IS NULL presenta además una forma negada, que nos permite resolver de forma más elegante la consulta original (la lista de empleados con jefe): Select NSS FROM Empleado WHERE NSSSupervisor IS NOT NULL Esta consulta se evalúa de esta manera: NSS Npila 1 2 3 4 Juan Pedro María Antonio Empleado Ap1 Ap2 … NSSSupervisor … Pérez Pérez López Blas Pérez Pi Botín Castro ... ... ... ... 1 3 ... ... ... ... NSS NSSSupervisor ¿ NSSSupervisor IS Fila NOT NULL ? seleccionada 1 (Nulo) Falso 2 1 Verdadero 3 (Nulo) Falso 4 3 Verdadero ...siendo ahora este el resultado final: Empleado NSS Npila Ap1 Ap2 … NSSSupervisor … 2 Pedro López Blas ... 1 ... 4 Antonio Botín Castro ... 3 ... NSS 2 4 ...ya que el predicado IS NOT NULL, asociado a un nombre de columna, presenta la siguiente evaluación: - Si el valor de la columna es nulo, IS NOT NULL se evaluará como Falso Si el valor de la columna no es nulo, IS NOT NULL se evaluará como Verdadero Condiciones compuestas Autor: Juan Ramón López Rodríguez 16 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 La cláusula WHERE permite especificar condiciones más complejas de consulta, por medio de las conectivas lógicas: AND , OR y NOT. Las conectivas lógicas permiten combinar dos o mas condiciones (simples o compuestas), de la siguiente forma: condición1 Verdadero Verdadero Falso Verdadero Falso Desconocido condición2 Verdadero Falso Falso Desconocido Desconocido Desconocido condicion1 AND condición2 Verdadero Falso Falso Desconocido Falso Desconocido condición1 Verdadero Falso Desconocido NOT (condición1) Falso Verdadero Desconocido condicion1 OR condición2 Verdadero Verdadero Falso Verdadero Desconocido Desconocido La mejor forma de entender la forma de especificar una condición de selección compuesta es con un ejemplo. Supongamos que pretendemos realizar la siguiente consulta: Ejemplo: Recuperar los NSS de todos aquellos empleados del departamento de Ventas que tienen jefe. En esta consulta tenemos que seleccionar a los empleados a mostrar de acuerdo con dos condiciones: - Por un lado, los empleados deben pertenecer al departamento de Ventas (D01) Por otro lado, los empleados deben tener un supervisor (un jefe) - Se trata claramente de una condición compuesta. La consulta que proporciona esta información es esta: Select NSS FROM Empleado WHERE NumDept=’D01’ AND NSSSupervisor IS NOT NULL Como se puede apreciar, se piden dos condiciones que deben cumplirse a la vez (de ahí que usemos la conectiva AND). La consulta se evalúa como sigue: Empleado NSS … NumDept NSSSupervisor 1 2 3 4 ... ... ... ... D01 D01 D02 D02 1 3 Condición2: ¿Condición1 Condición1: Fila ¿NSSSupervisor AND ¿NumDept=’D01’? Seleccionada IS NOT NULL? Condición2? Verdadero Falso Falso Verdadero Verdadero Verdadero Falso Falso Falso Falso Verdadero Falso Como se ve, solo hay un empleado que cumpla las dos condiciones. El resultado de la consulta sería este: Autor: Juan Ramón López Rodríguez 17 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais NSS … NumDept NSSSupervisor 2 ... D01 1 NSS 2 Supongamos ahora que la información solicitada es la siguiente: Ejemplo: Recuperar los NSS de todos aquellos empleados de la empresa que o bien pertenezcan al departamento de Ventas o bien tengan jefe. En este caso, las condiciones indicadas varían ligeramente: ya no se trata de dos condiciones que deban cumplirse juntas; ahora nos interesan los empleados que cumplan una cualquiera de ellas. Por lo tanto, la conectiva a utilizar es, en este caso, OR: Select NSS FROM Empleado WHERE NumDept=’D01’ OR NSSSupervisor IS NOT NULL Esta nueva consulta se evalúa como sigue: Empleado NSS … NumDept NSSSupervisor 1 2 3 4 ... ... ... ... D01 D01 D02 D02 1 3 Condición2: ¿Condición1 Condición1: Fila ¿NSSSupervisor OR ¿NumDept=’D01’? Seleccionada IS NOT NULL? Condición2? Verdadero Falso Verdadero Verdadero Verdadero Verdadero Falso Falso Falso Falso Verdadero Verdadero Como se ve, solo hay un empleado que no cumple ninguna de las dos condiciones, y que por lo tanto debe ser descartado. El resultado de la consulta sería este: NSS 1 2 4 … NumDept NSSSupervisor ... D01 ... D01 1 ... D02 3 NSS 1 2 4 Otro ejemplo podría ser este: Seleccionar a aquellos empleados que no trabajen en el departamento de Ventas. Se trata de una consulta ideal para el uso de NOT, ya que debemos establecer como condición que algo no se cumpla. Select distinct NSS FROM Empleado WHERE NOT(NumDept=’D01’) Empleado NSS … NumDept 1 ... D01 Autor: Juan Ramón López Rodríguez Condición1: Not (Condición1): Fila ¿NumDept=’D01’? ¿NOT (NumDept=’D01’)? Seleccionada Verdadero Falso 18 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais 2 3 4 ... ... ... D01 D02 D02 Verdadero Falso Falso Falso Verdadero Verdadero Como se puede ver, seleccionamos exclusivamente a aquellos empleados que no pertenecen a Ventas. Empleado NSS … NumDept 3 ... D02 4 ... D02 NSS 3 4 Analizaremos un último ejemplo, algo más complejo de lo que podría parecer en un principio: Seleccionar a los empleados cuyo jefe no es Juan. Aparentemente, esta consulta se resuelve fácilmente utilizando de nuevo el predicado NOT: Select NSS FROM Empleado WHERE NOT(NSSSupervisor=1) Es decir, seleccionamos a aquellos empleados cuyo jefe no tenga 1 por valor de NSS (que es el de Juan). Empleado NSS … NSSSupervisor 1 2 3 4 ... ... ... ... 1 3 NOT(Condición1): Condición1: Fila ¿NOT ( NSSSupervisor ¿NSSSupervisor=1? Seleccionada =1 ? Desconocido Desconocido Verdadero Falso Desconocido Desconocido Falso Verdadero Como se puede apreciar, estamos descartando las filas correspondientes a dos empleados (Juan y María) ¡que no tienen a Juan como jefe! 3; y que por lo tanto deberían aparecer en el resultado de la consulta. La culpa de que no aparezcan es de los valores nulos. Efectivamente, ni Juan ni María tienen jefe, por lo que NSSSupervisor toma para ambos el valor Nulo. Al comparar NSSSupervisor con 1 (el NSS de Juan), el resultado es desconocido, por lo que ambas filas resultan descartadas. Se impone por lo tanto una modificación de la consulta, para tratar convenientemente todos aquellos casos en los que NSSSupervisor sea Nulo. La forma de hacerlo es esta: Select NSS FROM Empleado WHERE NOT(NSSSupervisor=1) OR NSSSupervisor IS NULL 3 De hecho, ninguno de los dos tiene jefe. Autor: Juan Ramón López Rodríguez 19 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais Es decir, serán incluidos en el resultado todos aquellos empleados que no tengan jefe (NSSSupervisor IS NULL) o bien, si tienen jefe, su NSS no sea 1 (el de Juan) Empleado NSS … NSSSupervisor 1 2 3 4 ... ... ... ... 1 3 Condición1: NOT(Condición1): Condición2: ¿NOT(Condición1) Fila ¿NSSSupervisor ¿NOT (NSSSupervisor ¿NSSSupervisor OR Condición 2? seleccionada =1? =1) ? IS NULL? Desconocido Desconocido Verdadero Verdadero Verdadero Falso Falso Falso Desconocido Desconocido Verdadero Verdadero Falso Verdadero Falso Verdadero Ahora sí hemos conseguido descartar solamente a Pedro, que es el único empleado que tiene a Juan por jefe. Empleado NSS … 1 ... 3 ... 4 ... NSSSupervisor 3 NSS 1 3 4 Como hemos podido comprobar en este ejemplo, la presencia de valores nulos complica siempre la realización de consultas. Se trata de uno de los motivos por los que – como ya ha sido señalado en alguna ocasión – el diseño de las tablas de una BD debe ser analizado detenidamente para evitar en lo posible la necesidad del uso de valores nulos. Consultas sobre varias tablas Hasta ahora, todos los ejemplos que hemos visto se referían a consultas que permitían recuperar la información contenida en una única tabla. Sin embargo, en muchas ocasiones va a ser necesario combinar los datos almacenados en varias tablas para poder obtener la información que se necesite. Supongamos por ejemplo esta petición de información: Obtener los nombres de todos los empleados de la empresa, junto con el nombre de los departamentos en los que trabajan. La principal dificultad de escribir una consulta que obtenga esta información radica precisamente en que la información está distribuida en dos tablas: - El nombre de los empleados se encuentra en la tabla Empleado El nombre de los departamentos se encuentra en la tabla Departamento Sin embargo, ambas tablas incluyen una columna común: NumDept. Esta columna, en la tabla Empleado, nos permite representar/averiguar el número del departamento correspondiente a cada empleado. A partir de ese número, podemos localizar la fila correspondiente en la tabla Departamento y averiguar los datos del mismo. Para resolver el problema, SQL nos permite especificar dos o más tablas (separadas por comas) en la cláusula FROM; es decir, podemos especificar que queremos extraer la información desde dos o más tablas de la BD. Sin embargo, la evaluación de la consulta va a diferir ligeramente con respecto al mecanismo que habíamos visto hasta ahora. Dicho mecanismo de evaluación constaba de los siguientes pasos: Autor: Juan Ramón López Rodríguez 20 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 1. Determinar la tabla de origen, indicada en la cláusula FROM 2. Seleccionar aquellas filas que cumplen la condición o condiciones especificadas en la cláusula WHERE 3. Ordenar las filas de la tabla original de acuerdo con lo especificado en la cláusula ORDER BY 4. A partir de cada fila de la tabla original, generar una fila en la tabla resultante, a partir de la evaluación de las expresiones indicadas en la cláusula SELECT El mecanismo a seguir en el caso de consultas definidas sobre varias tablas va a ser ahora: 1. Determinar las tablas de origen, indicadas en la cláusula FROM 2. Combinar las tablas originales, de forma que se genere una tabla única sobre la que trabajar. 3. Seleccionar aquellas filas de la tabla original que cumplen la condición o condiciones especificadas en la cláusula WHERE 4. Ordenar las filas de la tabla original de acuerdo con lo especificado en la cláusula ORDER BY 5. A partir de cada fila de la tabla original, generar una fila en la tabla resultante, a partir de la evaluación de las expresiones indicadas en la cláusula SELECT Como se puede apreciar, los cambios (señalados en negrita) son mínimos: La esencia del cambio radica en que vamos a obtener, de las tablas originales, una nueva tabla, única, sobre la que trabajar. Una vez obtenida esa tabla, podremos continuar procediendo como habíamos visto hasta ahora: evaluando las cláusulas WHERE, ORDER BY y SELECT sobre una única tabla. Evidentemente, la clave del correcto funcionamiento de la consulta está en la forma en la que se realizará la combinación de las (dos o mas) tablas originales. La idea es combinar las filas de una tabla con las filas que tenga asociadas en el resto de tablas. En el caso de nuestro ejemplo, deberíamos intentar combinar cada fila correspondiente a un empleado con la fila correspondiente a su departamento. De esta forma, en la tabla combinada seguiríamos contando con una fila por cada empleado, que incluiría además toda la información relativa a su departamento. Autor: Juan Ramón López Rodríguez 21 Grao en Información e Documentación: Bases de datos documentais NSS 1 2 3 4 Empleado ... NumDept NSSSupervisor ... D01 ... D01 1 ... D02 ... D02 3 NSS 1 2 3 4 Curso 2013 – 2014 Departamento NumDept NomDept NSS FechaIniGerente D01 Ventas 1 01/01/2000 D02 Produccion 3 01/01/2004 Tabla Combinada ... NumDept NSSSupervisor NumDept NomDept NSS FechaIniGerente ... D01 D01 Ventas 1 01/01/2000 ... D01 1 D01 Ventas 1 01/01/2000 ... D02 D02 Produccion 2 01/01/2004 ... D02 3 D02 Produccion 2 01/01/2004 Como se puede apreciar, sería sencillo definir una consulta sobre la tabla combinada para recuperar la información que se solicita en el ejemplo. Esa tabla combinada se obtiene, en SQL, en dos pasos: 1. En primer lugar, se realiza el producto cartesiano de los conjuntos de filas de todas las tablas. Es decir, se establecen todas las combinaciones posibles de cada fila de una tabla con las filas de todas las demás tablas, ¡tengan o no sentido! En el caso de la consulta de nuestro ejemplo, sabemos ya que la cláusula FROM contendrá dos tablas: Empleado y Departamento. SELECT FROM Empleado, Departamento WHERE Esas dos tablas serán combinadas, dando lugar a una tabla única: cada fila de la tabla Empleado será combinada con todas y cada una de las filas de la tabla Departamento, dando lugar a una nueva fila en la tabla combinada. Es decir, si en la tabla Empleado tenemos 4 filas, y en la tabla Departamento tenemos 2 filas, la tabla combinada tendrá un total de 4 x 2 = 8 filas. Tabla Combinada: Paso 1 NSS 1 1 2 2 3 3 4 4 Origen: Tabla Empleado Origen: Tabla Departamento ... NumDept NSSSupervisor NumDept NomDept NSS FechaIniGerente ... D01 D01 Ventas 1 01/01/2000 ... D01 D02 Produccion 2 01/01/2004 ... D01 1 D01 Ventas 1 01/01/2000 ... D01 1 D02 Produccion 2 01/01/2004 ... D02 D01 Ventas 1 01/01/2000 ... D02 D02 Produccion 2 01/01/2004 ... D02 3 D01 Ventas 1 01/01/2000 ... D02 3 D02 Produccion 2 01/01/2004 Como se ve en la figura, en la tabla resultante del primer paso han sido incluidas las siguientes combinaciones: - La fila del empleado 1 (Juan) ha sido combinada con las filas de los departamentos D01 y D02 Autor: Juan Ramón López Rodríguez 22 Grao en Información e Documentación: Bases de datos documentais - Curso 2013 – 2014 La fila del empleado 2 (Pedro) ha sido combinada con las filas de los departamentos D01 y D02 La fila del empleado 3 (María) ha sido combinada con las filas de los departamentos D01 y D02 La fila del empleado 4 (Antonio) ha sido combinada con las filas de los departamentos D01 y D02 ...resultando un total de 8 filas, tal y como habíamos calculado 2. No todas la combinaciones realizadas tienen interés para nosotros. Atendiendo a la consulta que queremos realizar, sólo son relevantes aquellas en las que los datos de un empleado han sido combinados con los datos del departamento en el que trabaja. El segundo paso consiste en seleccionar aquellas combinaciones de interés, por medio del establecimiento de una o más condiciones de reunión: las condiciones que hacen válida una combinación de filas de diferentes tablas. ¿Cómo se especifican las condiciones de reunión? Aprovechando un mecanismo ya conocido: la cláusula WHERE. Ampliaremos las condiciones de esta cláusula incluyendo aquellas que convierten en válidas a las filas de la tabla combinada. En el caso de nuestro ejemplo, para nosotros serán válidas aquellas combinaciones de filas de empleado y departamento para las que el valor de NumDepto coincida. Esa será pues, la condición de reunión a establecer en la cláusula WHERE. SELECT FROM Empleado, Departamento WHERE NumDept = NumDept Un problema de combinar varias tablas es que la tabla combinada puede acabar incluyendo varias columnas con el mismo nombre. Nuestro ejemplo no podía ser menos y existen varias columnas en esa situación en la tabla combinada: NSS, procedente de la tabla Empleado (representa el NSS de cada empleado) y NSS, procedente de la tabla Departamento (que representa el NSS del director del departamento); NumDept, procedente de la tabla Empleado (que representa el número de departamento de cada empleado de la empresa), y NumDept, procedente de la tabla Departamento (que representa en número de cada departamento de la empresa). ¿Cómo distinguirlas cuando nos refiramos a ellas? (por ejemplo, en la condición de reunión NumDept = NumDept) Para solucionar esta aparente ambigüedad, lo que haremos será utilizar prefijos para designar a las columnas: cada nombre de columna, cuando la referenciemos, irá precedida del nombre de la tabla de la que provenga, separando ambos nombres por un punto (.) Así, la consulta de reunión de nuestro ejemplo pasa a ser... SELECT FROM Empleado, Departamento WHERE Empleado.NumDept = Departamento.NumDept …y de este modo resolvemos cualquier posible ambigüedad en cuanto a las columnas a las que nos referimos en la condición. Podemos así seleccionar las filas que son coherentes: Autor: Juan Ramón López Rodríguez 23 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais Tabla Combinada: Paso 2 Origen: Tabla Empleado Origen: Tabla Departamento NSS ... NumDept … NumDept NomDept … 1 ... D01 … D01 Ventas ... 1 ... D01 … D02 Produccion ... 2 ... D01 … D01 Ventas ... 2 ... D01 … D02 Produccion ... 3 ... D02 … D01 Ventas ... 3 ... D02 … D02 Produccion ... 4 ... D02 … D01 Ventas ... 4 ... D02 … D02 Produccion ... Empleado.NumDept = Departamento.NumDept Verdadero Falso Verdadero Falso Falso Verdadero Falso Verdadero Fila seleccionada Resultando la tabla combinada final: Tabla Combinada después del paso 2 Origen: Tabla Empleado NSS NPila ... NumDept 1 Juan ... D01 2 Pedro ... D01 3 María ... D02 4 Antonio ... D02 Origen: Tabla Departamento ... NumDept NomDept … ... D01 Ventas ... ... D01 Ventas ... ... D02 Produccion ... ... D02 Produccion ... Una vez obtenida la tabla combinada definitiva, es posible ya comprobar el resto de condiciones especificadas en la cláusula WHERE, evaluar las expresiones de la cláusula SELECT y calcular el resultado final SELECT Npila, NomDept FROM Empleado, Departamento WHERE Empleado.NumDept = Departamento.NumDept NSS NPila 1 Juan 2 Pedro 3 María 4 Antonio Tabla Combinada después del paso 2 ... NumDept ... NumDept NomDept ... D01 ... D01 Ventas ... D01 ... D01 Ventas ... D02 ... D02 Produccion ... D02 ... D02 Produccion … ... ... ... ... Resultado consulta NPila NomDept Juan Ventas Pedro Ventas María Produccion Antonio Produccion Es necesario observar que, de pretender incluir en el resultado el número del departamento, deberíamos especificar de cuál de las dos columnas con el mismo nombre de la tabla combinada pretenderíamos extraerlo. Las posibilidades serían dos: la columna procedente de Empleado, o la columna procedente de Departamento. Cualquiera de las dos opciones sería válida SELECT Npila, Empleado.NumDept, NomDept FROM Empleado, Departamento WHERE Empleado.NumDept = Departamento.NumDept SELECT Npila, Departamento.NumDept, NomDept FROM Empleado, Departamento WHERE Empleado.NumDept = Departamento.NumDept Consultas que involucran varias veces a la misma tabla. Autor: Juan Ramón López Rodríguez 24 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 ¿Qué sucede cuando tenemos una clave foránea que referencia a una clave primaria de la misma tabla? ¡Que las cosas se complican! Volvamos a nuestro ejemplo: la tabla Empleado contiene una clave foránea de ese tipo: NSSSupervisor. Esta columna permite almacenar, para cada empleado, el NSS de su jefe, que a su vez es un empleado y debe estar registrado en la tabla. Sin embargo, no se incluye una columna para poder registrar el nombre del jefe da cada empleado entre el resto de sus datos. Supongamos ahora que nos hacen llegar la siguiente petición: Para todos aquellos empleados de la empresa que tengan jefe, se necesita la lista de sus nombres y los nombres de sus jefes inmediatos. Es fácil pensar cómo obtener manualmente la información: - Se recuperan los datos de todos los empleados con jefe de la empresa: todas las filas de la tabla Empleado con NSSSupervisor no nulo. De cada fila, nos quedamos con el nombre del empleado (NPila) y el NSS de su supervisor (NSSSupervisor). Utilizamos el NSS del supervisor, y localizamos la fila que le corresponde en la tabla (de nuevo) Empleado. Recuperamos de la fila el nombre del supervisor (NPila) Como se puede ver, estamos dando dos usos a la tabla Empleado; o, dicho de otra manera, estamos contemplando la tabla desde dos puntos de vista: 1. Tabla que mantiene información sobre los empleados de la empresa. 2. Tabla que mantiene información sobre los jefes de la empresa. O lo que es lo mismo: estamos combinando una tabla ¡consigo misma! Este hecho sugiere una posible vía para la elaboración de una consulta SQL que permita obtener la información deseada: incluir dos veces la misma tabla (Empleado) en la cláusula FROM; y combinar las “dos” tablas de forma que cada fila de un empleado se una a la fila correspondiente a su jefe. De ese modo, la tabla resultante tendrá una fila por cada empleado de la empresa, e incluirá en cada una de ellas el nombre del empleado, y el nombre de su jefe: precisamente, la información que necesitamos. La consulta a realizar sería esta: SELECT Emp.Npila, Jefe.NPila FROM Empleado Emp, Empleado Jefe WHERE Emp.NSSSupervisor = Jefe.NSS Para poder entender la consulta, debemos aclarar una serie de cuestiones: - Incluir dos veces a Empleado la misma tabla en la cláusula FROM nos da la ilusión de contar con dos copias exactamente iguales de la tabla: una con información sobre empleados y otra con información sobre jefes. - Para poder diferenciar cada una de las “copias”, utilizaremos sendos alias de la tabla: nombres (apodos) que le daremos a la tabla original cada vez que la Autor: Juan Ramón López Rodríguez 25 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais incluyamos en la cláusula FROM, y que utilizaremos en todo el resto de la consulta para referirnos a cada una de las “copias” resultantes. En el ejemplo, usamos el alias Emp para referirnos a la tabla Empleado en su papel de contenedora de información sobre los empleados; y el alias Jefe para referirnos a Empleado en su papel de contenedora de información sobre los jefes - supervisores - de empleados. - Cada vez que debamos referirnos a una columna de alguna de las “copias”, usaremos el alias como prefijo para indicar de cuál de ellas. Si queremos acceder a un dato sobre un empleado, usamos la “copia” Emp; y si queremos referirnos a un dato sobre un jefe, usamos la “copia” Jefe. - Para combinar los datos de cada empleado con los datos de su jefe, establecemos la condición de reunión siguiente: una fila de la “copia” Emp y otra de la “copia” Jefe se unirán si la segunda representa al jefe del empleado representado por la primera: es decir, si el NSS de la segunda (Jefe.NSS) es igual al NSS del jefe indicado por la primera (Emp.NSSSupervisor). Podemos verlo mejor acudiendo a los datos, y viendo cómo se combinan. Partimos de dos “copias” idénticas de la tabla Empleado: Emp y Jefe NSS NPila 1 Juan 2 Pedro 3 María 4 Antonio Emp ... NSSSupervisor ... ... 1 ... ... 3 NSS NPila 1 Juan 2 Pedro 3 María 4 Antonio Jefe ... NSSSupervisor ... ... 1 ... ... 3 Al evaluar la consulta, combinamos las dos “copias”, resultando la tabla siguiente: NSS 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 Origen: Emp Origen: Jefe NPila ... NSSSupervisor NSS NPila ... NSSSupervisor Juan ... 1 Juan ... Juan ... 2 Pedro ... 1 Juan ... 3 María ... Juan ... 4 Antonio ... 3 Pedro ... 1 1 Juan ... Pedro ... 1 2 Pedro ... 1 Pedro ... 1 3 María ... Pedro ... 1 4 Antonio ... 3 María ... 1 Juan ... María ... 2 Pedro ... 1 María ... 3 María ... María ... 4 Antonio ... 3 Antonio ... 3 1 Juan ... Antonio ... 3 2 Pedro ... 1 Antonio ... 3 3 María ... Antonio ... 3 4 Antonio ... 3 Y al evaluar la condición de reunión, el resultado será este otro: Origen: Emp Origen: Jefe NSS NPila ... NSSSupervisor NSS NPila ... NSSSupervisor 1 1 Juan Juan ... ... Juan Pedro ... ... 1 2 Autor: Juan Ramón López Rodríguez 1 ¿Emp.NSSSupervisor Fila = Jefe.NSS? Seleccionada Desconocido Desconocido 26 Curso 2013 – 2014 Grao en Información e Documentación: Bases de datos documentais 1 1 2 2 2 2 3 3 3 3 4 4 4 4 Juan Juan Pedro Pedro Pedro Pedro María María María María Antonio Antonio Antonio Antonio ... ... ... ... ... ... ... ... ... ... ... ... ... ... 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 1 1 1 3 3 3 3 María Antonio Juan Pedro María Antonio Juan Pedro María Antonio Juan Pedro María Antonio ... ... ... ... ... ... ... ... ... ... ... ... ... ... 3 1 3 1 3 1 3 Desconocido Desconocido Verdadero Falso Falso Falso Desconocido Desconocido Desconocido Desconocido Falso Falso Verdadero Falso Nos quedamos, pues, con sólo dos filas, sobre las que evaluamos las expresiones del SELECT: Origen: Emp Origen: Jefe NSS NPila ... NSSSupervisor NSS NPila ... NSSSupervisor 2 Pedro ... 1 1 Juan ... 4 Antonio ... 3 3 María ... Emp.NPila Jefe.NPila Pedro Juan Antonio María Y conseguimos así la información que necesitábamos, con una consulta de lo más sencilla. Vistas Una vista, en SQL, es una consulta a la que se le asigna un nombre. De ese modo podemos utilizar una consulta como si fuese una tabla, e incluirla incluso en otras consultas. La utilidad principal de las vistas es proporcionar una manera de dar diferentes visiones de la BD a los diferentes usuarios de la misma. 4 Lo veremos con un ejemplo: comprobaremos como mediante una vista podemos ampliar la tabla Empleado permitiendo representar en ella un atributo derivado (la edad del empleado), calculada con una función especial de SQL (datediff) que permite calcular la diferencia en años entre dos fechas dadas. 5 La consulta que nos permite añadir esa columna a la tabla Empleado es esta: SELECT *, DateDiff("yyyy", FNac,Now()) AS Edad FROM Empleado ...con el siguiente resultado: NSS NPila 1 Juan 2 Pedro 3 María 4 Antonio Ap1 Ap2 Sexo Dirección Pérez Pérez H R/ Vilar 2 López Blas H R/ Fontes 12 Basco Pi M R/ Galicia 6 Botín Castro H Pza Galicia 1 FNac NumDept NSSSupervisor Edad 02/06/64 D01 40 23/12/50 D01 1 54 12/03/75 D02 29 13/01/65 D02 3 39 4 Recordar el nivel externo de la arquitectura de la información, ya visto anteriormente. Asumiremos que la función se comporta como debe, y no nos preocuparemos aquí de analizar su funcionamiento en detalle. 5 Autor: Juan Ramón López Rodríguez 27 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 Para convertir esta consulta en una vista, utilizamos la instrucción de SQL CREATE VIEW, que presenta la siguiente sintaxis: CREATE VIEW <Nombre vista> AS <Consulta Select> En el caso de nuestro ejemplo: CREATE VIEW EmpleadoEdad AS SELECT *, DateDiff("yyyy", FNac,Now()) AS Edad FROM Empleado Una vez definida la vista, ya podrá ser utilizada en cualquier consulta: SELECT * FROM EmpleadoEdad NOTA: Access no soporta la definición de vistas. En su lugar, todas las consultas creadas en Access se convierten implícitamente en una vista. Autor: Juan Ramón López Rodríguez 28 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 Apéndice: Mecanismo de evaluación de las consultas SELECT Se reproduce a continuación, de forma separada para comodidad del lector/a, la secuencia de evaluación de una sentencia SELECT: 1. Determinar las tablas de origen, indicadas en la cláusula FROM 2. Combinar las tablas originales, de forma que se genere una tabla única sobre la que trabajar. 3. Seleccionar aquellas filas de la tabla original que cumplen la condición o condiciones especificadas en la cláusula WHERE 4. Ordenar las filas de la tabla original de acuerdo con lo especificado en la cláusula ORDER BY 5. A partir de cada fila de la tabla original, generar una fila en la tabla resultante, a partir de la evaluación de las expresiones indicadas en la cláusula SELECT Autor: Juan Ramón López Rodríguez 29 Grao en Información e Documentación: Bases de datos documentais Curso 2013 – 2014 Bibliografía - R. Elmasri y S. Navathe. Fundamentos de los Sistemas de Bases de Datos (3ª edición). Addison-Wesley, 2002. E. Rivero, L. Martínez, J. Benavides, L. Reina y J. Olaizola. Introducción al SQL para Usuarios y Programadores. Thomson, 2002. A. Silberschatz, H. F. Korth y S. Sudarshan. Fundamentos de Bases de Datos (4ª edición). McGraw Hill, 2002 Autor: Juan Ramón López Rodríguez 30