SQL LEFT JOIN: conservar todas las filas de la tabla izquierda
Lección 5.3 · Tiempo de lectura: ~7 min · Tareas de práctica ↓
SQL LEFT JOIN devuelve cada fila de la tabla izquierda y las filas coincidentes de la tabla derecha; donde no hay coincidencia, las columnas de la tabla derecha son NULL. En esta lección aprenderás la sintaxis de LEFT JOIN, cómo encontrar filas sin coincidencia y el error en WHERE que convierte en silencio un LEFT JOIN en un INNER JOIN.
INNER JOIN descarta las filas sin coincidencia. Muchas veces son justamente las que necesitas: películas sin copias en stock, clientes sin pedidos este mes, productos que nunca se vendieron. LEFT JOIN las conserva.
Qué devuelve LEFT JOIN
- Cada fila de la tabla izquierda (la que va después de
FROM) aparece en el resultado al menos una vez. - Si una fila tiene coincidencias en la tabla derecha, se combina con cada una de ellas, como en
INNER JOIN. - Si una fila no tiene coincidencia, aparece una vez, y todas las columnas de la tabla derecha son
NULL.
LEFT JOIN y LEFT OUTER JOIN son lo mismo; la palabra OUTER es opcional.
Sintaxis básica
SELECT left_table.column1, right_table.column2
FROM left_table
LEFT JOIN right_table ON left_table.key_column = right_table.key_column;
Películas y sus copias
Sakila tiene 1000 películas, pero no todas están en stock. Con LEFT JOIN, las películas sin copias se quedan en el resultado:
SELECT f.film_id, f.title, i.inventory_id, i.store_id
FROM film AS f
LEFT JOIN inventory AS i ON i.film_id = f.film_id
ORDER BY i.inventory_id IS NULL DESC, f.title
LIMIT 10;
Resultado: primero aparecen las películas sin copias; su inventory_id y su store_id son NULL.
Con INNER JOIN, la misma consulta perdería esas 42 películas.
Encontrar filas sin coincidencia
Para encontrar solo las filas sin coincidencia, agrega una condición WHERE que compruebe NULL en una columna de la tabla derecha. Comprueba la columna clave de la tabla derecha: solo es NULL cuando no coincidió ninguna fila.
SELECT f.film_id, f.title
FROM film AS f
LEFT JOIN inventory AS i ON i.film_id = f.film_id
WHERE i.inventory_id IS NULL
ORDER BY f.title;
Resultado: las 42 películas que no tienen copias en ninguna tienda.
Este patrón se llama anti-join. Responde preguntas del tipo "qué falta". Otro ejemplo, copias que nunca se alquilaron:
SELECT i.inventory_id, f.title, i.store_id
FROM inventory AS i
INNER JOIN film AS f ON f.film_id = i.film_id
LEFT JOIN rental AS r ON r.inventory_id = i.inventory_id
WHERE r.rental_id IS NULL;
Resultado: una copia que nunca se alquiló.
La trampa del WHERE
Un filtro sobre la tabla derecha puesto en WHERE elimina las filas en las que las columnas de esa tabla son NULL, y el LEFT JOIN se comporta como un INNER JOIN. Compara dos consultas: ambas deberían listar a todos los clientes con sus pagos hechos a partir del 23 de agosto de 2005.
-- Mal: los clientes sin esos pagos desaparecen
SELECT c.customer_id, c.last_name, p.amount, p.payment_date
FROM customer AS c
LEFT JOIN payment AS p ON p.customer_id = c.customer_id
WHERE p.payment_date >= '2005-08-23'
ORDER BY c.customer_id;
-- Bien: la condición forma parte del join
SELECT c.customer_id, c.last_name, p.amount, p.payment_date
FROM customer AS c
LEFT JOIN payment AS p ON p.customer_id = c.customer_id
AND p.payment_date >= '2005-08-23'
ORDER BY c.customer_id;
Resultado: la primera consulta devuelve solo a los clientes que pagaron en ese período. La segunda conserva a los 599 clientes; los que no pagaron a fines de agosto tienen NULL en amount y payment_date.
La regla: las condiciones sobre la tabla derecha que deben limitar las coincidencias van en ON. Las condiciones sobre la tabla izquierda, que deben quitar filas del resultado, van en WHERE. La única condición sobre la tabla derecha que va en WHERE es IS NULL para un anti-join.
El orden de las tablas importa
En INNER JOIN, intercambiar las tablas no cambia el resultado. En LEFT JOIN, sí: la tabla que va después de FROM es la que conserva todas sus filas. film LEFT JOIN inventory conserva todas las películas; inventory LEFT JOIN film conserva todas las copias, y cada copia tiene una película, así que se pierden las películas sin copias.
Conclusiones clave:
LEFT JOINconserva cada fila de la tabla izquierda; las filas sin coincidencia recibenNULLen las columnas de la tabla derecha.LEFT JOINyLEFT OUTER JOINson lo mismo.LEFT JOIN ... WHERE right_key IS NULLencuentra filas sin coincidencia (un anti-join).- Un filtro sobre la tabla derecha en
WHEREconvierte unLEFT JOINen unINNER JOIN; ponlo enON. - La tabla que va después de
FROMes la que conserva sus filas.
Preguntas frecuentes
¿Cuál es la diferencia entre INNER JOIN y LEFT JOIN?
INNER JOIN devuelve solo las filas que tienen coincidencia en ambas tablas. LEFT JOIN también devuelve las filas de la tabla izquierda sin coincidencia y completa las columnas de la derecha con NULL.
¿LEFT JOIN es lo mismo que LEFT OUTER JOIN?
Sí. OUTER es opcional, y ambas formas devuelven el mismo resultado en cualquier base de datos.
¿Por qué mi LEFT JOIN funciona como un INNER JOIN?
Lo más probable es que la cláusula WHERE tenga una condición sobre una columna de la tabla derecha. En las filas sin coincidencia esa columna es NULL, la condición no es verdadera y las filas se eliminan. Mueve la condición a la cláusula ON.