El JOIN es la operación que convierte un montón de tablas en una base de datos relacional. Y aun así, la diferencia entre INNER, LEFT, RIGHT y FULL sigue generando pánico en entrevistas y bugs en producción. Con dos tablas pequeñas y resultados visibles, se acaba el misterio para siempre.
Las tablas de ejemplo
Dos tablas mínimas: autores y libros. Fíjate en las asimetrías — son la clave de todo:
autores
| id | nombre |
|---|---|
| 1 | Ana |
| 2 | Borja |
| 3 | Carmen |
libros
| id | titulo | autor_id |
|---|---|---|
| 10 | Niebla | 1 (Ana) |
| 11 | Bruma | 1 (Ana) |
| 12 | Mareas | 2 (Borja) |
| 13 | Huella | NULL |
Carmen no tiene libros. "Huella" no tiene autor (NULL — libro huérfano). Cada join existe para responder una pregunta distinta sobre estos huecos.
INNER JOIN: solo lo que coincide
SELECT a.nombre, l.titulo
FROM autores a
INNER JOIN libros l ON l.autor_id = a.id;
| nombre | titulo |
|---|---|
| Ana | Niebla |
| Ana | Bruma |
| Borja | Mareas |
Solo filas con pareja en ambas tablas. Carmen desaparece (sin libros), "Huella" desaparece (sin autor). Es el join por defecto mental — y el más usado porque la mayoría de preguntas son "dame las coincidencias". Ojo: Ana aparece DOS veces porque tiene dos libros; el resultado de un join es filas combinadas, no entidades agrupadas.
LEFT JOIN: conserva toda la izquierda
SELECT a.nombre, l.titulo
FROM autores a
LEFT JOIN libros l ON l.autor_id = a.id;
| nombre | titulo |
|---|---|
| Ana | Niebla |
| Ana | Bruma |
| Borja | Mareas |
| Carmen | NULL |
Toda la tabla izquierda sobrevive, rellenando con NULL donde no hay pareja. La pregunta que responde: "todos los autores, y su libro si tienen".
Su aplicación estrella — encontrar los que NO tienen nada:
SELECT a.nombre
FROM autores a
LEFT JOIN libros l ON l.autor_id = a.id
WHERE l.id IS NULL;
-- Resultado: Carmen
Este patrón ("left join + where null") es LA forma idiomática de anti-join: elementos de A sin correspondiente en B. Autores sin libros, clientes sin pedidos, usuarios sin login reciente.
RIGHT y FULL: completar el cuadro
RIGHT JOIN es el LEFT invertido: conserva toda la tabla derecha.
SELECT a.nombre, l.titulo
FROM autores a
RIGHT JOIN libros l ON l.autor_id = a.id;
| nombre | titulo |
|---|---|
| Ana | Niebla |
| Ana | Bruma |
| Borja | Mareas |
| NULL | Huella |
En la práctica casi nadie escribe RIGHT JOIN — se invierte el orden de tablas y se usa LEFT, que lee más natural. Existe por simetría del estándar.
FULL OUTER JOIN conserva ambos lados: Carmen Y "Huella" aparecen, cada uno con NULLs en su hueco. Para "muéstrame todo de ambos mundos con sus coincidencias donde las haya" — inventarios vs movimientos, usuarios vs sesiones.
CROSS JOIN: el producto cartesiano
Sin condición ON: cada fila × cada fila. 3 autores × 4 libros = 12 filas. Parece inútil hasta que necesitas generar todas las combinaciones: todas las fechas × todos los productos para un informe mensual, o todas las parejas para comparaciones cruzadas. Úsalo deliberadamente; accidentalmente (ON mal escrito u olvidado) genera explosiones de millones de filas que tumban servidores.
Los errores clásicos
Filtrar la tabla izquierda en el WHERE mata al LEFT JOIN:
-- Quiere: todos los autores con sus libros publicados en 2026 (si tienen)
-- MAL:
SELECT a.nombre, l.titulo
FROM autores a LEFT JOIN libros l ON l.autor_id = a.id
WHERE l.anio = 2026; -- ¡Carmen desaparece otra vez!
-- BIEN: mover la condición al ON
SELECT a.nombre, l.titulo
FROM autores a LEFT JOIN libros l
ON l.autor_id = a.id AND l.anio = 2026; -- Carmen vuelve con NULL
Condición en WHERE = filtro DESPUÉS del join (los NULL quedan fuera). Condición en ON = define el emparejamiento (los sin-pareja sobreviven). Es LA distinción del LEFT JOIN.
Contar con JOIN duplica filas: COUNT(*) sobre un join autores-libros cuenta libros, no autores. Para contar autores con libros: COUNT(DISTINCT a.id). El bug silencioso más frecuente en dashboards.
NULL nunca iguala: si autor_id pudiera ser 0 u otro centinela en vez de NULL, los joins cambian de comportamiento. Normaliza nulos antes de razonar resultados.
Formatear consultas grandes
Un join triple con subconsultas sin formato es ilegible — y lo ilegible esconde bugs. Pega tu consulta en nuestro formateador SQL para verla estructurada antes de modificarla, y si va lenta, el siguiente paso natural es revisar índices y planes de ejecución.
Preguntas frecuentes
¿INNER JOIN y JOIN son lo mismo? Sí, JOIN a secas implica INNER. Escribirlo completo ayuda a leer intención.
¿Puedo encadenar varios JOIN? Sí, y es lo normal: pedidos → clientes → países → regiones. Cada ON une contra el resultado acumulado hasta ese punto; con LEFT encadenados, el orden importa muchísimo.
¿USING y NATURAL JOIN? USING (id) azucar sintáctico cuando la columna se llama igual (y colapsa la columna duplicada). NATURAL JOIN une por TODAS las columnas homónimas automáticamente — cómodo hasta peligroso: añadir una columna llamada igual rompe consultas silenciosamente. Evítalo.
Formatea tus consultas con joins complejos usando nuestro SQL Formatter, gratis y directamente en tu navegador.