Publicado en

JOINs en SQL: combina tablas en una consulta

Dos tablas SQL unidas por un INNER JOIN sobre fondo oscuro

Una base de datos relacional no vale mucho si no puedes relacionar sus tablas. El nombre del cliente que realizó un pedido está en usuarios. El pedido en sí, en pedidos. Para cruzar esa información en una sola consulta existen los JOINs.

¿Cómo funciona un JOIN?

Un JOIN combina filas de dos tablas basándose en una condición. Esa condición se especifica con la cláusula ON e indica qué columnas de cada tabla representan la misma información:

SELECT columnas
FROM tabla_a
JOIN tabla_b ON tabla_a.clave = tabla_b.clave;

En la práctica, la condición casi siempre relaciona una clave primaria con una clave foránea. Por ejemplo, la columna id_usuario de la tabla pedidos apunta a la clave primaria id_usuario de la tabla usuarios. Esa es la columna que une ambas tablas.

Hay cuatro variantes de JOIN, y la diferencia entre ellas es qué ocurre con las filas que no tienen correspondencia en la otra tabla.

Los cuatro tipos de JOIN en SQL: INNER JOIN solo devuelve coincidencias, LEFT JOIN devuelve todas las filas de la tabla izquierda, RIGHT JOIN todas las de la derecha, FULL OUTER JOIN todas de ambas

INNER JOIN: solo los que coinciden

INNER JOIN es el tipo más habitual. Devuelve únicamente las filas que tienen correspondencia en ambas tablas. Si un usuario no tiene pedidos, no aparece en el resultado.

SELECT usuarios.nombre, pedidos.id_pedido, pedidos.total
FROM usuarios
INNER JOIN pedidos ON usuarios.id_usuario = pedidos.id_usuario;

La palabra INNER es opcional: JOIN a secas funciona igual y se comporta como INNER JOIN.

LEFT JOIN: todos los de la izquierda

LEFT JOIN devuelve todas las filas de la tabla de la izquierda (FROM) y las filas coincidentes de la tabla de la derecha. Donde no hay coincidencia, las columnas de la tabla derecha aparecen como NULL.

SELECT usuarios.nombre, pedidos.id_pedido, pedidos.total
FROM usuarios
LEFT JOIN pedidos ON usuarios.id_usuario = pedidos.id_usuario;

Con este JOIN, María sí aparece en el resultado, pero con id_pedido y total a NULL porque no tiene pedidos. Es el JOIN adecuado cuando quieres listar todos los registros de una tabla independientemente de si tienen datos relacionados en la otra.

Casos de uso habituales: clientes sin pedidos, artículos sin stock, usuarios sin perfil completado.

RIGHT JOIN: todos los de la derecha

RIGHT JOIN es el espejo de LEFT JOIN: devuelve todas las filas de la tabla de la derecha y las coincidentes de la izquierda.

SELECT usuarios.nombre, pedidos.id_pedido, pedidos.total
FROM usuarios
RIGHT JOIN pedidos ON usuarios.id_usuario = pedidos.id_usuario;

En la práctica se usa poco porque cualquier RIGHT JOIN puede reescribirse como un LEFT JOIN invirtiendo el orden de las tablas, lo que resulta más legible. Su principal utilidad aparece cuando estás construyendo consultas largas y cambiar el orden de las tablas sería más disruptivo.

FULL OUTER JOIN: todos de ambas tablas

FULL OUTER JOIN combina LEFT JOIN y RIGHT JOIN: devuelve todas las filas de ambas tablas. Donde no hay coincidencia en un lado, las columnas correspondientes aparecen como NULL.

SELECT usuarios.nombre, pedidos.id_pedido, pedidos.total
FROM usuarios
FULL OUTER JOIN pedidos ON usuarios.id_usuario = pedidos.id_usuario;

Es útil para detectar inconsistencias o registros huérfanos en ambas tablas. Nota: MySQL no implementa FULL OUTER JOIN directamente; se simula combinando un LEFT JOIN y un RIGHT JOIN con UNION.

Alias de tabla

Cuando las consultas incluyen varios JOINs, repetir el nombre completo de la tabla en cada columna resulta tedioso. Los alias de tabla solucionan esto:

SELECT u.nombre, p.id_pedido, p.total
FROM usuarios AS u
INNER JOIN pedidos AS p ON u.id_usuario = p.id_usuario;

El alias se declara justo después del nombre de la tabla con AS (o sin él, que también funciona). A partir de ese punto, en toda la consulta puedes usar la forma corta. Además de ahorrar escritura, los alias son imprescindibles cuando unes una tabla consigo misma, ya que sin ellos SQL no puede distinguir a qué instancia te refieres.

JOIN entre más de dos tablas

Los JOINs se encadenan. Para obtener los productos incluidos en cada pedido junto con el nombre del usuario que lo realizó, necesitas tres tablas:

SELECT u.nombre, p.id_pedido, pr.nombre AS producto
FROM usuarios AS u
INNER JOIN pedidos AS p ON u.id_usuario = p.id_usuario
INNER JOIN pedidos_productos AS pp ON p.id_pedido = pp.id_pedido
INNER JOIN productos AS pr ON pp.id_producto = pr.id_producto;

Cada JOIN añade una tabla más al resultado. El orden importa: cada nueva tabla se une con alguna ya presente en la consulta a través de la condición ON.

A medida que las tablas crecen en volumen, la velocidad de estas consultas deja de ser automática. Una búsqueda que cruza millones de filas sin ninguna guía estructural puede tardar segundos en lugar de milisegundos. Esa guía se llama índice.