SQL EXISTS: filtrar filas por registros relacionados
SQL EXISTS devuelve verdadero cuando una subconsulta correlacionada encuentra al menos una fila coincidente. Úsalo para filtrar filas padre por la presencia (o ausencia) de filas hijas relacionadas sin duplicar resultados como puede ocurrir con un JOIN. Los planificadores de consultas suelen ejecutar EXISTS como un semi-join, así que pueden detener el trabajo de la subconsulta después de la primera coincidencia.
Ejemplo de SQL EXISTS para filtrar por existencia de filas
Salida:
La salida aparecerá aquí...
Salida:
+------+
| name |
+------+
| Alma |
| Cara |
+------+
2 row(s)
Por qué EXISTS devuelve Alma y Cara
- Se crean dos tablas:
customerscontiene tres personas,orderscontiene tres pedidos vinculados porcustomer_id. WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id)ejecuta la subconsulta una vez por cada fila de cliente. Si existe al menos un pedido coincidente, el cliente pasa el filtro.SELECT 1dentro de la subconsulta es una convención: la base de datos ignora la lista seleccionada y solo comprueba si alguna fila cumple la condición.- Ben no tiene pedidos, así que su subconsulta devuelve cero filas y EXISTS se evalúa como falso. Alma y Cara tienen al menos un pedido y aparecen en el resultado.
A diferencia de un INNER JOIN, EXISTS nunca duplica la fila externa. Alma tiene dos pedidos y aun así aparece una sola vez porque EXISTS solo pregunta “¿existe una coincidencia?”, no “¿cuántas?”.
NOT EXISTS vs NOT IN: el problema con NULL
SQL NOT EXISTS (escrito como NOT EXISTS) es la opción segura para anti-joins en columnas que aceptan NULL. Cuando una subconsulta devuelve valores NULL, NOT IN produce resultados inesperados porque cualquier comparación con NULL devuelve desconocido:
-- Supón que orders tiene una fila con customer_id NULL
-- NOT IN descarta en silencio TODAS las filas
SELECT name FROM customers
WHERE id NOT IN (SELECT customer_id FROM orders);
-- NOT EXISTS sigue funcionando correctamente
SELECT name FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
NOT IN trata id NOT IN (1, 3, NULL) como id <> 1 AND id <> 3 AND id <> NULL. La última comparación siempre es desconocida, así que todo el predicado nunca es verdadero y la consulta devuelve cero filas. NOT EXISTS evita esto porque comprueba existencia de filas, no igualdad de valores.
Errores comunes con SQL EXISTS
Falta el predicado de correlación
Si la subconsulta no está correlacionada con la fila externa, EXISTS se vuelve una prueba constante: cuando existe cualquier pedido, todos los clientes coinciden.
-- Incorrecto: no está correlacionado con la fila externa
SELECT c.name FROM customers c
WHERE EXISTS (SELECT 1 FROM orders);
-- Correcto: correlacionado por customer_id
SELECT c.name FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
Usar JOIN cuando solo importa la existencia
Un INNER JOIN devuelve una fila por coincidencia, así que los clientes con varios pedidos aparecen varias veces.
SELECT c.name
FROM customers c
JOIN orders o ON o.customer_id = c.id;
Usa EXISTS salvo que necesites columnas de orders.
EXISTS vs IN vs JOIN
| Enfoque | Úsalo cuando… |
|---|---|
EXISTS (subquery) | Compruebas existencia de filas relacionadas; la subconsulta está correlacionada |
NOT EXISTS (subquery) | Anti-join, especialmente con claves foráneas que aceptan NULL |
IN (subquery) | Comparas contra un conjunto pequeño de valores no nulos |
INNER JOIN | Necesitas columnas de ambas tablas en el resultado |
LEFT JOIN ... IS NULL | Alternativa para anti-join; a veces la prefieren los planificadores |
Regla: usa EXISTS para preguntas de “¿existe una fila relacionada?”. Cambia a JOIN cuando necesites datos de ambos lados.
Notas de rendimiento
EXISTS suele planificarse como un semi-join. Un índice en la columna de correlación (orders.customer_id aquí) permite que el motor busque la primera fila coincidente por cliente en lugar de recorrer orders completo. NOT EXISTS se beneficia del mismo índice. Si EXISTS es lento, revisa el plan de ejecución y si la columna de correlación está indexada.
FAQ
¿EXISTS se detiene después de la primera coincidencia?
En términos lógicos, el resultado pasa a verdadero tan pronto como existe una fila que cumple la condición. Muchas bases de datos lo implementan como un semi-join con corte tras la primera coincidencia, pero la estrategia exacta depende del planificador de consultas. Revisa el plan de ejecución si necesitas confirmar qué hace tu base de datos.
¿Se puede usar EXISTS en UPDATE y DELETE?
Sí. UPDATE ... WHERE EXISTS (subquery) y DELETE ... WHERE EXISTS (subquery) limitan qué filas se modifican o eliminan según la existencia de filas relacionadas. Mantén el mismo predicado de correlación que usarías en un SELECT, para que cada fila objetivo compruebe solo sus filas relacionadas.
¿Cuál es la diferencia entre EXISTS e IN en SQL?
EXISTS comprueba si una subconsulta (normalmente correlacionada) devuelve alguna fila. IN compara un valor contra un conjunto de resultados. EXISTS funciona de forma natural con la correlación de la consulta externa, y muchos motores pueden detenerse tras la primera coincidencia; IN encaja bien con listas literales pequeñas o comprobaciones de pertenencia no correlacionadas. Para anti-joins en columnas que aceptan NULL, prefiere NOT EXISTS frente a NOT IN.