Inicio‎ > ‎SQL‎ > ‎Lecciones SQL‎ > ‎T07 Conjuntos‎ > ‎

Conjuntos 2

El operador EXISTS

EXISTS es un operador de un único argumento y cuyo resultado es un valor de verdad, informa de la presencia o no de tuplas en una tabla. 

     [NOT] EXISTS (orden select) 

El operador exists nos informa de si una subconsulta ha obtenido algún resultado: devuelve verdadero si hay al menos una tupla en la relación derivada y falso si la relación derivada es vacía.


¿Tenemos profesores?

select exists (select 1 from profesores) respuesta

respuesta
1

Puesto que no necesitamos nada de la tabla profesores salvo saber si hay o no filas, por eso nos basta con "select 1": el resultado de la subconsulta sería tantas filas con "1" como filas haya en la tabla profesores.

Es más habitual componer una condición que nos permita filtrar filas.


Todos los datos de las asignaturas que son impartidas por algún profesor

select * from asignaturas a where exists (select 1 from imparte i where i.asignatura=a.codigo)
codigodescripcioncreditoscreditosp
DGBDDISEÑO Y GESTION DE BASES DE DATOS6.03.0
FBDFUNDAMENTOS DE LAS BASES DE DATOS6.01.5
PCPROGRAMACION CONCURRENTE6.01.5


Evidentemente, el resultado sería el mismo si pidiéramos

select * from asignaturas where codigo IN (select asignatura from imparte)

Eficiencia

Aunque para la cantidad de filas que estamos manejando tanto en la BD Ejemplo como en TiendaOnLine la diferencia es irrelevante, el uso de exists puede ser adecuado para mejorar el rendimiento de ciertas consultas. Sea, por ejemplo:

select distinct nombre
from profesores p, imparte i
where p.dni = i.dni;


En realidad, sólo nos interesa saber el nombre de los profesores que imparten alguna asignatura, sin reparar en cuáles son esas asignaturas. Para eso, es mejor utilizar:

select nombre from profesores p
where exists (select 1 from imparte where dni = p.dni);

nombre
EVA GOMEZ
RAFAEL ROMERO


La ventaja de esta segunda consulta es que la subconsulta sólo necesita devolver una fila por cada profesor, mientras que la primera primero obtiene la concatenación de todos los códigos de asignatura con su profesor correspondiente y después proyecta sobre la columna nombre. 

Podemos suponer un estado de la base de datos que contuviera 1000 asignaturas, y que los 3 profesores imparten todas las asignaturas: la primera consulta trabajaría con 3000 filas, mientras que la segunda no necesitaría más de 3.

No obstante, lo dicho aquí debe considerarse como un apunte sobre la necesidad en ciertos entornos de mejorar el rendimiento de aquellas consultas que son críticas por su frecuencia o por un gran volumen de datos, esto es, "ayudar" al optimizador de consultas. 


select nombre from profesores p
where exists
(select codigo from asignaturas a
where exists
(select asignatura from prepara pp
where pp.asignatura=a.codigo and p.dni=pp.dni)
)

sería equivalente a "nombre de los profesores que preparan alguna asignatura", que se soluciona mucho más fácil como

select nombre
from profesores p, prepara pp
where p.dni=pp.dni

nombre
EVA GOMEZ
RAFAEL ROMERO


O si negamos solo uno de los exists


Nombre de los profesores que no preparan todas las asignaturas (que existe al menos una asignatura que no prepara)

select nombre from profesores p
where exists
(select codigo from asignaturas a
where not exists
(select asignatura from prepara pp
where pp.asignatura=a.codigo and p.dni=pp.dni)
)

nombre
EVA GOMEZ
MANUEL PALOMAR



Alternativas

A veces, el resultado buscado permite otro tipo de soluciones.

Nombre de los profesores que preparan todas las asignaturas.

select nombre from profesores p, prepara pp
where p.dni = pp.dni
group by p.dni, nombre
having count(*) = (select count(*) from asignaturas);



Nombre de los profesores que no preparan ninguna asignatura.

select nombre from profesores p
where not exists
(select codigo from asignaturas a
where exists
(select asignatura from prepara pp
where pp.asignatura=a.codigo and p.dni=pp.dni)
);
 
select nombre from profesores p
where not exists
(select asignatura from prepara pp
where p.dni=pp.dni);
  

Realmente, la alternativa más clara y fácil de entender es esta:

select nombre from profesores
where dni NOT IN (select dni from prepara);


nombre
MANUEL PALOMAR





División

NOTA: el operador división no se va a exigir en ninguna prueba desde el curso 2013-14. El texto que sigue se mantiene como material adicional para quienes tengan interés en ampliar conocimientos de álgebra relacional y SQL.

La división como operador definido en el álgebra relacional nos da como resultado "algo que se relaciona con todos los que cumplen una condición". Por ejemplo, 

IMPARTE[asignatura, dni] ÷ (PROFESORES[dni])

Esta expresión daría como resultado los códigos de las asignaturas que son impartidas por todos los profesores de mi base de datos. No existe, la división, como tal operador en SQL por lo que debemos simularlo con exists.


La división del álgebra relacional con EXISTS

Uno de los posibles usos, aunque ciertamente confuso al principio, es el de resolver consultas del tipo "x hace algo con todos los y de nuestra base de datos".

Supongamos una tabla adicional en nuestra BD Ejemplo, PREPARA, que es una relación muchos a muchos entre asignaturas y profesores, y que podría representar qué profesores intervienen en la preparación de cada asignatura. Su contenido es el que se muestra a continuación:


Profesores que preparan todas las asignaturas.

select nombre from profesores p
where not exists
(select codigo from asignaturas a
where not exists
(select asignatura from prepara pp
where pp.asignatura=a.codigo and p.dni=pp.dni)
)

nombre
RAFAEL ROMERO



Vamos a reformular la consulta siguiendo las apariciones del operador exists dentro de las sucesivas órdenes select:

"Nombre de los profesores tales que no hay ninguna asignatura que no prepare él".

Supongamos que la forma que tiene el SGBD de resolver esta sentencia es la siguiente :
  1. En la primera select recorremos la tabla de profesores.
  2. Para cada profesor de la anterior, la segunda select recorre la tabla de asignaturas.
  3. Para cada profesor y asignatura de las anteriores comprueba que el primero prepara la segunda.
Comments