EMPLEADO(dni,nombree,direccion, sexo,salario,fecha_nac,dni_super↑,numerod↑) DEPARTAMENTO(numerod,nombred,dni_dir↑, fecha_ini) PROYECTO(numerop,nombrep,lugar,numerod↑) TRABAJA_EN(dni↑,numerop↑,horas) 54 EXISTS y NOT EXISTS Empleados que no trabajan en el proyecto 527. SELECT dni FROM TRABAJA_EN WHERE numerop <> 527 SELECT dni FROM EMPLEADO WHERE NOT EXISTS (SELECT * FROM TRABAJA_EN WHERE TRABAJA_EN.dni = EMPLEADO.dni AND numerop = 527) 55 1 EXIST y NOT EXISTS (II) Siempre preceden a subconsulta EXISTS - cierto si el conjunto resultante de la subconsulta no está vacío NOT EXISTS - cierto si vacío En el ejemplo la subconsulta selecciona todas las filas de TRABAJA_EN que tienen el mismo NSS que la fila que se está examinando en la consulta principal y el NUMEROP igual a 527. Si ese conjunto está vacío, se selecciona la fila correspondiente 56 EXISTS y NOT EXISTS (III) Lo anterior era consulta correlacionada. Si queremos no correlacionada SELECT dni FROM EMPLEADO WHERE dni NOT IN (SELECT dni FROM TRABAJA_EN WHERE numerop = 527) 57 2 EXISTS y NOT EXISTS (IV) ¿Por qué usar NOT EXISTS? Única forma de expresar consultas que contengan el cuantificador “todos” - Ejemplo: empleados que trabajan en todos los proyectos = empleados tales que no hay ningún proyecto en el que no trabajen 1. Proyectos en los que el empleado 1234 no trabaja SELECT nombrep FROM PROYECTO WHERE NOT EXISTS (SELECT * FROM TRABAJA_EN WHERE TRABAJA_EN.numerop = PROYECTO.numerop AND TRABAJA_EN.dni = 1234) 58 EXISTS y NOT EXISTS (V) 2. Generalizar la consulta a un NSS variable SELECT nombree FROM EMPLEADO WHERE NOT EXISTS (SELECT * FROM PROYECTO WHERE NOT EXISTS (SELECT * FROM TRABAJA_EN WHERE TRABAJA_EN.numerop = PROYECTO.numerop AND TRABAJA_EN.dni = EMPLEADO.dni) Proyectos en los que el empleado X no está trabajando. Si vacío ⇒ nos vale ese empleado NOT EXISTS puede usarse para expresar los tipos de consultas para los que se utiliza el operador división del álgebra relacional 59 3 Ejemplos (I) Si el departamento 122 está ubicado en la calle de Alcalá, obtener por orden alfabético los nombres de aquéllos de sus empleados cuyo salario supere al salario medio de su departamento. SELECT nomem FROM EMPLEADO WHERE numde = 122 AND salario > (SELECT AVG(salario) FROM EMPLEADO WHERE numde = 122) AND EXISTS (SELECT * FROM DEPARTAMENTO WHERE numde = 122 AND numce IN (SELECT numce FROM CENTRO WHERE señas LIKE ‘%ALCALA%’) ORDER BY nomem 60 El operador UNIQUE Cierto si no hay dos filas iguales en la tabla Empleados que trabajan en más de un proyecto SELECT DISTINCT apellido FROM EMPLEADO WHERE NOT UNIQUE (SELECT nump FROM TRABAJA_EN WHERE TRABAJA_EN.nsse = EMPLEADO.nss) 61 4 El operador MATCH fila MATCH [UNIQUE] tabla Cierto si existe al menos una fila en la tabla igual a fila. (Si aparece UNIQUE - exactamente una fila) Empleados que no tienen un departamento válido SELECT nomem FROM EMPLEADO WHERE NOT (EMPLEADO.numde MATCH UNIQUE (SELECT numde FROM departamento)) 62 Tablas anidadas Hallar los departamentos y el número de empleados que tienen aquellos en los que la media de los salarios de sus empleados sea inferior a 2900 euros. SELECT numerod, totalemp FROM (SELECT A.numde AS numerod, AVG(salario) AS salmedio, COUNT(*) AS totalemp FROM EMPLEADO NJ DEPARTAMENTO GROUP BY numde) AS XXX WHERE salmedio < 2900 ORDER BY numerod Es obligatorio asignarle un nombre a la tabla anidada 63 5 Tablas anidadas (II) Para los departamentos 100 y 110, hallar el valor medio de los salarios medios por departamento. SELECT AVG(premed) AS MEDIA FROM (SELECT AVG(salario) AS PREMED FROM EMPLEADO WHERE numde IN (100, 110) GROUP BY numde) AS T1 64 Tablas anidadas (III) Construir dos grupos con los departamentos. Uno con aquellos en los que el presupuesto es superior en 10 veces a la suma de los salarios de sus empleados y otro con los que es inferior. Hallar para cada grupo el presupuesto medio. SELECT GRUPO, AVG(pres) AS PREMEDIO FROM (SELECT presupuesto*1000 AS PRES, `MAYOR’ AS GRUPO FROM DEPARTAMENTO D1 WHERE presupuesto*1000 > (SELECT SUM(salario) * 10 FROM EMPLEADO E1 WHERE E1.numde = D1.numde) UNION ALL SELECT presupuesto*1000 AS PRES, `MENOR’ AS GRUPO FROM DEPARTAMENTO D2 WHERE presupuesto*1000 > (SELECT SUM(salario) * 10 FROM EMPLEADO E2 WHERE E2.numde = D2.numde) ) AS GRUPOS GROUP BY GRUPO ORDER BY GRUPO 65 6 Tablas anidadas (IV) Hallar para los departamentos del centro 10, su número, su presupuesto y la suma de salarios de sus empleados. SELECT A.numde AS NUMDEP, presupuesto, SUMSALAR FROM DEPARTAMENTO A, TABLE (SELECT SUM(salario) AS SUMSALAR FROM EMPLEADO B WHERE B.numde = A.numde) AS XXX WHERE numce = 10 ORDER BY NUMDEP 66 Equivalente a Hallar para los departamentos del centro 10, su número, su presupuesto y la suma de salarios de sus empleados. SELECT A.numde AS NUMDEP, presupuesto, SUMSALAR FROM DEPARTAMENTO A, (SELECT numde, SUM(salario) AS SUMSALAR FROM EMPLEADO GROUP BY numde) AS T1 WHERE numce = 10 AND A.numde = T1.numde ORDER BY NUMDEP 67 7 Y También a Hallar para los departamentos del centro 10, su número, su presupuesto y la suma de salarios de sus empleados. SELECT numde, presupuesto, SUM(salario) AS SUMSALAR FROM DEPARTAMENTO NJ EMPLEADO WHERE numce = 10 GROUP BY numde, presupuesto ORDER BY numde 68 Tablas anidadas (V) SELECT numem FROM (SELECT numem, fecna, salario FROM (SELECT * FROM EMPLEADO WHERE numde = 121) AS T1 WHERE salario < 5000 ) AS T2 WHERE fecna < ‘1950-01-01’ ORDER BY numem SELECT numem FROM EMPLEADO WHERE numde = 121 AND salario < 5000 AND fecna < `1950-01-01’ ORDER BY numem 69 8 Referencias correlacionadas Cuando en una subconsulta se especifica un nombre de columna, el SGBD debe saber sin ambigüedad en qué tabla se encuentra esta columna a la que nos referimos. Para ello el sistema busca la primera tabla que contenga una columna con el nombre especificado siguiendo el siguiente orden ¾ Las tablas que aparecen antes en la propia cláusula FROM de la sentencia correlacionada ¾ Las tablas de la cláusula FROM de la primera sentencia antecedente ¾ Se recorren consecutivamente las tablas antecedentes hasta llegar a la sentencia externa 70 Referencias correlacionadas (II) En tablas anidadas si queremos que la búsqueda se realice hacia los niveles superiores hay que poner la palabra TABLE. Si no se pone TABLE, se limita la búsqueda a las tablas de la propia cláusula FROM Ejemplo válido: referencia correlacionada T1.C1 SELECT T1.C1, T3.C3 FROM T AS T1, TABLE (SELECT * FROM T AS T2 WHERE T2.C1 = T1.C1) AS T3 WHERE T1.C2 = T3.C2 71 9 Referencias correlacionadas (III) Ejemplo inválido: referencia correlacionada T1.C1 SELECT T1.C1, T3.C3 FROM TABLE (SELECT * FROM T AS T2 WHERE T2.C1 = T1.C1) AS T3, T AS T1 WHERE T1.C2 = T3.C2 Ejemplo inválido: referencia correlacionada T1.C1 SELECT T1.C1, T3.C3 FROM T AS T1, (SELECT * FROM T AS T2 WHERE T2.C1 = T1.C1) AS T3 WHERE T1.C2 = T3.C2 72 Referencias correlacionadas (IV) Hallar para los departamentos del centro 10, su número, su presupuesto y la suma de salarios de sus empleados. SELECT A.numde, presupuesto, SUMSALAR FROM DEPARTAMENTO A, TABLE (SELECT SUM(salario) AS SUMSALAR FROM EMPLEADO B WHERE B.numde = A.numde) AS XXX WHERE numce = 10 ORDER BY numde referencia correlacionada: A.numde 73 10