La trampa de WHERE en un outer join
Descubra por qué filtrar en WHERE una columna de un outer join lo convierte silenciosamente en un inner join
La trampa de WHERE en un outer join es una lección gratuita de SQL Interview Prep en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de SQL Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de SQL Interview Prep incluye 4 lecciones en total.
La trampa que atrapa a todo el mundo
Este es el error de joins externos más común que los entrevistadores suelen provocar: «Muestre todos los clientes y sus pedidos de 2024, incluidos los clientes sin pedidos de 2024».
El candidato escribe un LEFT JOIN y después añade un filtro de fecha en WHERE; los clientes sin pedidos de 2024 desaparecen silenciosamente. El LEFT JOIN se degrada silenciosamente a un INNER JOIN. Comprender por qué ocurre es una señal de experiencia avanzada.
La consulta con errores
Este es el error. Parece razonable: conservar todos los clientes, unir sus pedidos y filtrar los de 2024.
Pero los clientes sin pedidos, o sin pedidos de 2024, desaparecen del resultado. Se incumple el requisito de incluirlos.
-- BUG: drops customers with no 2024 order
SELECT c.name, o.id, o.order_date
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.order_date >= '2024-01-01';NULL invalida el filtro
Recuerde el orden de las operaciones: primero se ejecuta JOIN, que produce filas en las que los clientes sin coincidencia tienen NULL en todas las columnas de pedidos. Después se ejecuta WHERE.
Para un cliente sin coincidencia, o.order_date es NULL, por lo que o.order_date >= '2024-01-01' se evalúa como UNKNOWN, no como verdadero. WHERE conserva solo las filas cuyo resultado es TRUE, por lo que las filas con NULL se filtran, exactamente las filas que LEFT JOIN se esforzaba por conservar.
El filtro no supera NULL
Cualquier comparación con NULL produce UNKNOWN: NULL >= '2024-01-01' es UNKNOWN, NULL = 5 es UNKNOWN e incluso NULL <> 5 es UNKNOWN.
Como WHERE solo deja pasar las filas cuyo resultado es TRUE, todas las filas conservadas sin coincidencia se descartan. El propósito completo del join externo queda anulado por un único predicado WHERE sobre una columna de la tabla derecha.
La solución: filtrar en ON
Mueva el filtro a la cláusula ON. Allí pasa a formar parte de la condición de coincidencia, aplicada antes de conservar las filas, por lo que los clientes sin coincidencia siguen sobreviviendo con NULL.
-- CORRECT: filter lives in ON
SELECT c.name, o.id, o.order_date
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
AND o.order_date >= '2024-01-01';
-- customers with no 2024 order: kept, NULL orderON frente a WHERE en una frase
La regla que debe repetir en una entrevista:
En la tabla preservada (externa), las condiciones sobre la otra tabla deben ir en ON; las condiciones sobre la propia tabla preservada deben ir en WHERE.
ONdecide qué se considera una coincidencia (se ejecuta durante el join).WHEREfiltra las filas finales (se ejecuta después y elimina las filas con NULL).
Resultados lado a lado
Mismos datos, dos ubicaciones y respuestas diferentes. Supongamos que Carol no tiene ningún pedido de 2024.
- Filtro en WHERE: Carol desaparece. En la práctica, es un INNER JOIN.
- Filtro en ON: Carol aparece una vez con las columnas de pedidos en NULL; se cumple el requisito.
La diferencia en la salida es precisamente el objetivo de esta trampa.
-- ON version output
-- Alice | 50 | 2024-03-01
-- Bob | 20 | 2024-05-02
-- Carol | NULL | NULL <-- preservedCuándo WHERE sí es correcto
No todo uso de WHERE en un join externo es un error. Filtrar la tabla preservada es correcto; no intervienen los NULL generados por el join.
Además, el anti-join de la lección anterior utiliza intencionadamente WHERE o.id IS NULL para aprovechar exactamente este comportamiento. La clave está en saber en qué caso se encuentra.
-- Fine: filtering the preserved (left) table
SELECT c.name, o.id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE c.country = 'US';Heurística para detectarlo
Al revisar un join externo, examine la cláusula WHERE en busca de predicados sobre la tabla no preservada (excepto las comprobaciones IS NULL de anti-join).
Si ve o.someColumn = ... o una comprobación de rango o igualdad sobre el lado externo en WHERE, sospeche que se trata de esta trampa. Pregúntese: «¿Esto convierte mi LEFT JOIN en un INNER JOIN?» Normalmente, sí.
Varias condiciones
Puede combinar ambas ubicaciones. Las condiciones de coincidencia sobre la tabla derecha van en ON; un filtro posterior genuino sobre la tabla izquierda va en WHERE. Ambas condiciones conviven sin problemas.
SELECT c.name, o.id, o.amount
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
AND o.amount > 100 -- match condition
WHERE c.signup_year = 2023; -- preserved-table filterCómo explicarlo en voz alta
En la entrevista, describa el mecanismo, no solo la solución:
«El JOIN se ejecuta primero y rellena con NULL las columnas derechas sin coincidencia. Un predicado de WHERE sobre esas columnas se evalúa como UNKNOWN para las filas con NULL, y WHERE descarta las filas cuyo resultado no es verdadero, por lo que el outer join se convierte en un inner join. Colocar el predicado en ON lo mantiene como condición de coincidencia y conserva las filas sin coincidencia». Esa explicación siempre funciona.
Comprobación rápida
Debe enumerar todos los clientes y únicamente sus pedidos de 2024, incluidos los clientes que no tuvieron ninguno.
Resumen
Filtrar una columna de la tabla no preservada en WHERE convierte silenciosamente un outer join en un inner join, porque los NULL de las filas sin coincidencia no superan el predicado (UNKNOWN) y WHERE los descarta.
- Las condiciones de coincidencia sobre la tabla externa van en
ON. - Los filtros sobre la tabla preservada van en
WHERE. IS NULLen WHERE es el anti-join intencionado, no la trampa.- Explique el orden de las operaciones para demostrar que lo comprende.
Preguntas frecuentes
¿La lección «La trampa de WHERE en un outer join» es gratis?
Sí — el texto completo de «La trampa de WHERE en un outer join» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de SQL Interview Prep, actualiza a CoddyKit PRO. El curso de SQL Interview Prep incluye 4 lecciones en total.
¿Qué aprenderé en «La trampa de WHERE en un outer join»?
Descubra por qué filtrar en WHERE una columna de un outer join lo convierte silenciosamente en un inner join Practicas SQL Interview Prep con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar SQL Interview Prep?
No se requiere experiencia previa. SQL Interview Prep en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «La trampa de WHERE en un outer join»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de SQL Interview Prep?
Sí. Cada lección de SQL Interview Prep incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- LEFT JOIN y conservación de filas sin coincidencia
- Semántica de RIGHT y FULL OUTER JOIN
- Encontrar filas sin coincidencia (anti-join)
- La trampa de WHERE en un outer join