EXISTS responde a una pregunta de sí o no: ¿esta subconsulta devuelve alguna fila? Se usa en el WHERE para quedarse con las filas que tienen (o no tienen) algo relacionado en otra tabla: clientes con pedidos, productos sin ventas, usuarios sin actividad…
SELECT columnas
FROM tabla1 t1
WHERE [NOT] EXISTS (
SELECT 1
FROM tabla2 t2
WHERE t2.columna = t1.columna
);
Lo que devuelva el SELECT de dentro da igual: EXISTS solo mira si hay filas. Por convención se escribe SELECT 1.
Clientes con al menos un pedido
La subconsulta está correlacionada: usa C.idClientes, de la consulta exterior, así que se evalúa para cada cliente.
| idClientes | nombre | apellidos |
|---|---|---|
| 1 | Fernando | García Rodriguez |
| 2 | María | Lopez ruiz |
| 3 | Ana | Fernandez Montero |
| 4 | Luis | Sanchez García |
| 5 | Alejandro | Valero Martinez |
Lo mismo se podría hacer con un JOIN, pero María y Luis saldrían dos veces, una por pedido, y habría que añadir DISTINCT. EXISTS devuelve cada cliente una sola vez.
Clientes sin pedidos: NOT EXISTS
| idClientes | nombre | apellidos |
|---|---|---|
| 6 | Paloma | Sanz Valdivia |
| 7 | Ignacio | Herrero Dominguez |
La trampa de NOT IN con NULL
Parece que esta consulta debería devolver lo mismo que la anterior:
Ejecútala: no devuelve ninguna fila. El motivo es el pedido del Horno Balay, que tiene idClientes a NULL. Para SQL, 6 NOT IN (3, 2, 2, 1, 4, 4, 5, NULL) significa “6 es distinto de 3 y de 2 y … y de NULL”, y comparar con NULL nunca es verdadero. Basta un solo NULL en la subconsulta para que NOT IN no devuelva nada.
NOT EXISTS no tiene ese problema, porque la condición P.idClientes = C.idClientes simplemente no se cumple para el pedido sin cliente.
NOT IN con una subconsulta, filtra los nulos: NOT IN (SELECT idClientes FROM Pedidos WHERE idClientes IS NOT NULL). O mejor, usa NOT EXISTS.EXISTS con más condiciones
La subconsulta puede llevar cualquier filtro. Clientes que han comprado alguna consola:
| nombre | apellidos |
|---|---|
| Alejandro | Valero Martinez |
| María | Lopez ruiz |
EXISTS, IN o JOIN
| Necesitas… | Usa |
|---|---|
| Filtrar filas que tienen algo relacionado | EXISTS o IN (con datos sin NULL, el resultado es el mismo) |
| Filtrar filas que no tienen nada relacionado | NOT EXISTS |
| Mostrar columnas de las dos tablas | JOIN |
| Comparar con una lista fija de valores | IN ('a', 'b', 'c') |
En SQL Server el optimizador suele convertir EXISTS e IN en el mismo plan de ejecución, así que la elección tiene más que ver con la claridad y con el comportamiento ante NULL que con la velocidad.
Practica
- Lista los productos cuyo cliente tiene cuenta registrada (
cuenta IS NOT NULL). - Encuentra los clientes que no han hecho ningún pedido después del 1 de agosto de 2022.
- Arregla la consulta de
NOT INpara que devuelva a Paloma e Ignacio.