SQL LEFT JOIN: filas con coincidencia opcional

SQL LEFT JOIN devuelve cada fila de la tabla izquierda y adjunta las filas coincidentes de la tabla derecha. En términos de SQL, es un SQL outer join: cuando no existe coincidencia, las columnas del lado derecho se rellenan con NULL. Úsalo cuando necesites todos los registros de una tabla, exista o no información relacionada, por ejemplo al listar todos los clientes hayan hecho pedidos o no. LEFT JOIN y LEFT OUTER JOIN son palabras clave idénticas; OUTER es opcional.

Ejemplo de SQL LEFT JOIN para devolver todas las filas

Salida:

La salida aparecerá aquí...

Salida:

+---------+-------+
| cliente | total |
+---------+-------+
| Alma    | 79    |
| Alma    | 150   |
| Ben     | NULL  |
| Cara    | 45    |
+---------+-------+
4 row(s)

Cómo funciona este ejemplo

  1. customers contiene tres personas; orders contiene tres pedidos enlazados por customer_id.
  2. LEFT JOIN orders o ON o.customer_id = c.id empareja cada cliente con cada pedido que coincide con su id. Alma tiene dos pedidos, por eso genera dos filas de salida.
  3. Ben no tiene pedidos. LEFT JOIN conserva su fila y rellena o.total con NULL en lugar de excluirlo del resultado (que es lo que haría INNER JOIN).
  4. ORDER BY c.id, o.id mantiene la salida agrupada por cliente y estable dentro de cada cliente. El NULL en la columna total de Ben indica ausencia de coincidencia, no un pedido con valor cero.

ON vs WHERE: por qué importa dónde filtras

Poner un filtro de la tabla derecha en WHERE en lugar de ON es el error más común con LEFT JOIN: convierte silenciosamente el outer join en un inner join.

-- Incorrecto: WHERE elimina a Ben porque su o.total es NULL
SELECT c.name, o.total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.total > 50;

-- Correcto: ON filtra durante la coincidencia del join; Ben se conserva con NULL
SELECT c.name, o.total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id AND o.total > 50;

Las condiciones en ON se evalúan durante la unión: las filas izquierdas sin coincidencia siguen apareciendo con NULL. WHERE se aplica después de la unión, así que elimina cualquier fila donde la columna derecha sea NULL, justo las filas que LEFT JOIN estaba diseñado para conservar.

Anti-join: encontrar filas sin coincidencia

LEFT JOIN combinado con una comprobación IS NULL sobre una columna de la tabla derecha es una forma estándar de encontrar registros relacionados faltantes:

SELECT c.name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;

Esto devuelve solo a Ben, el cliente con cero pedidos. El patrón funciona porque o.id es NULL únicamente para filas izquierdas sin coincidencia. NOT EXISTS logra el mismo resultado y puede ser más claro cuando no necesitas columnas de la tabla derecha en la salida.

LEFT JOIN vs INNER JOIN

LEFT JOININNER JOIN
Todas las filas de la izquierda, NULL para columnas derechas sin coincidenciaSolo filas que coinciden en ambos lados
Conteo de filas >= conteo de filas de la tabla izquierdaConteo de filas <= conteo de filas de la tabla más pequeña
Úsalo cuando las filas sin coincidencia tienen significado (reportes, comprobaciones de integridad)Úsalo cuando cada fila del resultado debe tener datos válidos de ambas tablas

Regla: empieza con LEFT JOIN cuando sea importante conservar todas las filas de la izquierda. Cambia a INNER JOIN cuando las filas sin coincidencia no importan o son inválidas.

Errores comunes con SQL LEFT JOIN

Multiplicación de filas en joins uno a muchos

LEFT JOIN produce una fila de salida por cada par coincidente. Si un cliente tiene diez pedidos, ese cliente aparece diez veces. Agregar sin tener esto en cuenta infla los totales.

-- Incorrecto: cuenta filas de pedidos, no clientes
SELECT COUNT(*) FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;

-- Correcto: cuenta clientes distintos
SELECT COUNT(DISTINCT c.id) FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;

Usar SELECT * con joins

SELECT * en una consulta con join devuelve nombres de columna duplicados (por ejemplo, c.id y o.id), lo que causa confusión en el código de aplicación. Lista siempre las columnas que necesitas.

Notas de rendimiento

Indexa la clave de unión en la tabla derecha (orders.customer_id) para que el motor pueda buscar coincidencias en lugar de escanear. Para tablas derechas grandes donde solo importa un subconjunto de filas, prefiltra con una subconsulta o mueve el filtro a la cláusula ON, no a WHERE, para reducir el trabajo del join sin romper la semántica de LEFT JOIN.

Preguntas frecuentes

¿Cuál es la diferencia entre LEFT JOIN y LEFT OUTER JOIN?

Ninguna. LEFT JOIN y LEFT OUTER JOIN son sinónimos definidos por el estándar SQL. Todas las bases de datos principales (PostgreSQL, MySQL, SQLite, SQL Server, Oracle) los tratan igual. La mayoría de desarrolladores omiten OUTER por brevedad.

¿Por qué mi LEFT JOIN devuelve menos filas después de agregar una cláusula WHERE?

Un filtro WHERE sobre una columna de la tabla derecha elimina las filas extendidas con NULL, y convierte el LEFT JOIN en un INNER JOIN efectivo. Mueve la condición a la cláusula ON para conservar en el resultado las filas izquierdas sin coincidencia.

¿Cuándo debo usar LEFT JOIN en lugar de INNER JOIN?

Usa LEFT JOIN cuando las filas del lado izquierdo deban aparecer en la salida independientemente de coincidencias: reportes de completitud, comprobaciones de datos faltantes y enriquecimiento opcional. Usa INNER JOIN cuando solo las filas coincidentes sean válidas y debas excluir las no coincidentes.