Skip to main content

Uniones en SQL: una guía completa sobre los tipos, las diferencias y cuándo utilizar cada una

Las uniones SQL son una de las características más potentes —y más malinterpretadas— de las bases de datos relacionales. Esta guía analiza en profundidad todos los tipos de unión, con ejemplos reales, tablas comparativas y orientaciones claras sobre cuándo utilizar cada una de ellas.

18 min read
Uniones en SQL: una guía completa sobre los tipos, las diferencias y cuándo utilizar cada una

Las uniones son el mecanismo por el que las bases de datos relacionales deben su nombre. El objetivo fundamental de separar los datos en tablas distintas y normalizadas es poder combinarlas cuando sea necesario, extrayendo exactamente la parte de datos relacionados que se necesita, en el formato que se requiera. Comprender a fondo las uniones es imprescindible para cualquiera que trabaje en serio con SQL. Es la habilidad que distingue las consultas que funcionan de las que funcionan correctamente.

Esta guía abarca todos los tipos de unión estándar —INNER, LEFT, RIGHT, FULL OUTER, CROSS y SELF— con ejemplos prácticos, tablas de resultados y una orientación clara sobre cuándo es adecuado utilizar cada uno. Al finalizar, deberías ser capaz de analizar un problema de datos y saber de inmediato qué unión, o combinación de uniones, te dará la respuesta correcta.

El esquema de ejemplo

Todos los ejemplos de esta guía utilizan las mismas dos tablas, lo que permite realizar comparaciones claras y directamente comparables.

clientes

customer_id nombre ciudad
1 Alice Nguyen Sídney
2 Bob Martins Melbourne
3 Carol White Brisbane
4 David Kim Sídney

pedidos

id_pedido id_cliente producto importe
101 1 Portátil 1200,00
102 1 Ratón 45,00
103 2 Teclado 89,00
104 5 Monitor 399,00

Hay algunos aspectos que conviene destacar: el cliente 3 (Carol) y el cliente 4 (David) no tienen pedidos. El pedido 104 hace referencia al customer_id 5, que no existe en la tabla de clientes. Estos casos extremos son los que hacen que las diferencias entre los tipos de unión sean significativas.

INNER JOIN

Una INNER JOIN devuelve únicamente las filas en las que hay un valor coincidente en ambas tablas. Si una fila de la tabla de la izquierda no tiene coincidencia en la tabla de la derecha, se excluye. Si una fila de la tabla de la derecha no tiene coincidencia en la tabla de la izquierda, también se excluye.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;

Resultado:

customer_id name order_id product amount
1 Alice Nguyen 101 Portátil 1200,00
1 Alice Nguyen 102 Ratón 45,00
2 Bob Martins 103 Teclado 89,00

Fíjate en lo que falta: Carol y David (clientes 3 y 4) no aparecen porque no tienen pedidos que coincidan. El pedido 104 no aparece porque el customer_id 5 no existe en la tabla de clientes. El INNER JOIN es la intersección: solo se conservan las filas que coinciden en ambos lados.

Cuándo utilizarlo: INNER JOIN es la opción adecuada cuando solo te interesan los registros que tienen una relación en ambas tablas. Informes sobre clientes que han realizado pedidos, productos que se han vendido, empleados que han sido asignados a proyectos… cualquier escenario en el que las filas sin coincidencia sean irrelevantes para la consulta.

La trampa: Si utilizas un INNER JOIN cuando en realidad necesitas todos los registros de un lado, perderás datos sin darte cuenta. La consulta se ejecuta sin errores, pero los resultados son incompletos. Esta es una de las causas más comunes de informes incorrectos en SQL.


LEFT JOIN (LEFT OUTER JOIN)

Un LEFT JOIN devuelve todas las filas de la tabla de la izquierda, más las filas coincidentes de la tabla de la derecha. Cuando no hay coincidencia en la tabla de la derecha, las columnas del lado derecho se rellenan con NULL.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id;

Resultado:

customer_id name order_id product amount
1 Alice Nguyen 101 Portátil 1200,00
1 Alice Nguyen 102 Ratón 45,00
2 Bob Martins 103 Teclado 89,00
3 Carol White NULL NULL NULL
4 David Kim NULL NULL NULL

Ahora aparecen Carol y David, con valores NULL en las columnas de pedido. El pedido 104 sigue sin aparecer: no tiene ningún cliente con el que coincida, y la tabla de la izquierda aquí es la de clientes, no la de pedidos.

Cuándo utilizarlo: LEFT JOIN es la unión más utilizada después de INNER JOIN. Úsala siempre que quieras todos los registros de la tabla principal (izquierda), independientemente de si tienen una coincidencia en la tabla secundaria (derecha). Listas de clientes con su pedido más reciente (o NULL si nunca han realizado un pedido), productos con su nivel de stock actual (o NULL si aún no están en stock), usuarios con los datos de su perfil (o NULL si el perfil aún no se ha creado).

Búsqueda de filas sin coincidencia: LEFT JOIN combinado con una cláusula WHERE que filtre por NULL es el patrón estándar para encontrar registros sin coincidencia:

-- Buscar clientes que nunca hayan realizado un pedido
SELECT c.customer_id, c.name
FROM customers c
LEFT JOIN pedidos o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;

Resultado:

customer_id nombre
3 Carol White
4 David Kim

Este es un enfoque más limpio y, a menudo, más eficaz que utilizar subconsultas NOT IN o NOT EXISTS para la misma tarea.


UNIÓN A LA DERECHA (RIGHT OUTER JOIN)

Una UNIÓN A LA DERECHA es la imagen especular de una UNIÓN A LA IZQUIERDA. Devuelve todas las filas de la tabla de la derecha, más las filas coincidentes de la tabla de la izquierda. Cuando no hay coincidencia en la tabla de la izquierda, las columnas del lado izquierdo son NULL.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

Resultado:

customer_id name order_id product amount
1 Alice Nguyen 101 Ordenador portátil 1200,00
1 Alice Nguyen 102 Ratón 45,00
2 Bob Martins 103 Teclado 89,00
NULL NULL 104 Monitor 399,00

Ahora aparece el pedido 104, con valores NULL en las columnas de cliente porque el customer_id 5 no existe. Carol y David ya no están: no tienen pedidos, y la tabla de la derecha (pedidos) determina el resultado.

Cuándo utilizarlo: El RIGHT JOIN es menos habitual en la práctica, por una sencilla razón: cualquier RIGHT JOIN puede reescribirse como un LEFT JOIN intercambiando el orden de las tablas. La mayoría de los desarrolladores consideran que el LEFT JOIN es más legible porque se ajusta a la dirección natural de lectura: «dame todo lo que haya en esta tabla, más lo que coincida de aquella».

-- Estas dos consultas devuelven resultados idénticos:

-- RIGHT JOIN
SELECT c.name, o.product
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

-- LEFT JOIN equivalente (estilo preferido)
SELECT c.name, o.product
FROM orders o
LEFT JOIN customers c ON c.customer_id = o.customer_id;

Utiliza RIGHT JOIN cuando la consulta resulte más legible de esa forma, o cuando trabajes en un código que lo utilice de forma sistemática. Nunca lo utilices simplemente porque hayas aprendido que existe.


FULL OUTER JOIN

Un FULL OUTER JOIN devuelve todas las filas de ambas tablas. Cuando hay una coincidencia, se rellenan las columnas de ambos lados. Cuando no hay coincidencia en ninguno de los lados, las columnas del lado que no coincide son NULL.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
FULL OUTER JOIN orders o ON c.customer_id = o.customer_id;

Resultado:

customer_id name order_id product amount
1 Alice Nguyen 101 Ordenador portátil 1200,00
1 Alice Nguyen 102 Ratón 45,00
2 Bob Martins 103 Teclado 89,00
3 Carol White NULL NULL NULL
4 David Kim NULL NULL NULL
NULL NULL 104 Monitor 399,00

Aparecen todas las filas de ambas tablas. Las filas coincidentes se unen. Las filas no coincidentes de cualquiera de los dos lados aparecen con valores NULL en el otro lado.

Cuándo utilizarlo: La UNIÓN EXTERNA COMPLETA (FULL OUTER JOIN) es la opción adecuada cuando necesitas ver todo —tanto lo que coincide como lo que no— de ambos lados simultáneamente. Reconciliación de datos entre dos sistemas, detección de discrepancias entre una fuente y un destino, auditoría de lo que existe en una tabla pero no en la otra. Es menos habitual que INNER JOIN o LEFT JOIN, pero insustituible cuando se necesita.

Nota sobre MySQL: MySQL no admite de forma nativa la sintaxis de FULL OUTER JOIN. La solución habitual consiste en utilizar UNION con un LEFT JOIN y un RIGHT JOIN:

SELECT c.customer_id, c.name, o.order_id, o.product
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id

UNION

SELECT c.customer_id, c.name, o.order_id, o.product
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

PostgreSQL, SQL Server y la mayoría de las demás bases de datos admiten directamente el FULL OUTER JOIN.

Extreme close-up of programming code on a screen showing various technical elements


CROSS JOIN

Un CROSS JOIN devuelve el producto cartesiano de las dos tablas: cada fila de la tabla de la izquierda combinada con cada fila de la tabla de la derecha. No hay condición ON, ya que se devuelve cada combinación independientemente de cualquier relación.

SELECT
c.name,
o.product
FROM customers c
CROSS JOIN orders o;

Con 4 clientes y 4 pedidos, esto devuelve 4 × 4 = 16 filas:

name product
Alice Nguyen Portátil
Alice Nguyen Ratón
Alice Nguyen Teclado
Alice Nguyen Monitor
Bob Martins Portátil
Bob Martins Ratón
... ...

El resultado completo es de 16 filas. Con 100 filas × 100 filas, son 10 000. Con 1 000 × 1 000, son 1 000 000. Las CROSS JOIN crecen exponencialmente, por lo que deben utilizarse con precaución.

Cuándo utilizarlo: El CROSS JOIN tiene casos de uso reales. Generar todas las combinaciones de tallas y colores para un catálogo de productos. Crear una tabla de dimensiones de fechas cruzando una lista de años con una lista de días. Generar datos de prueba que requieran todas las permutaciones. Emparejar a cada comercial con cada región para crear una matriz de cobertura.

El CROSS JOIN accidental: Uno de los errores más peligrosos en SQL es un CROSS JOIN accidental causado por una condición JOIN ausente o incorrecta. Si te olvidas de la cláusula ON o realizas accidentalmente una unión con una condición que siempre se evalúa como verdadera, puedes obtener millones de filas a partir de dos tablas relativamente pequeñas. Comprueba siempre el recuento de filas cuando trabajes con múltiples uniones.


SELF JOIN

Un SELF JOIN no es un tipo de unión distinto en la sintaxis SQL, sino cualquier unión en la que una tabla se une consigo misma. Se utiliza una unión normal (INNER, LEFT u otra), pero ambos lados de la unión hacen referencia a la misma tabla con alias diferentes.

El caso de uso clásico son los datos jerárquicos o recursivos: una tabla employees en la que cada fila tiene un manager_id que hace referencia a otro employee_id de la misma tabla.

Consideremos esta tabla «employees»:

employees

employee_id name manager_id
1 Sarah Chen NULL
2 James Okafor 1
3 Maria Lopez 1
4 Tom Brennan 2
5 Yuki Tanaka 2

Sarah es la directora general y no tiene jefe. James y María dependen de Sarah. Tom y Yuki dependen de James.

SELECT
e.nombre AS empleado,
m.nombre AS jefe
FROM empleados e
LEFT JOIN empleados m ON e.id_jefe = m.id_empleado;

Resultado:

empleado jefe
Sarah Chen NULL
James Okafor Sarah Chen
María López Sarah Chen
Tom Brennan James Okafor
Yuki Tanaka James Okafor

Utilizamos LEFT JOIN para que Sarah (que no tiene jefe) siga apareciendo en los resultados con un jefe NULL, en lugar de quedar excluida por un INNER JOIN.

Otros casos de uso de la autounión: encontrar registros duplicados en una tabla, identificar filas que compartan un valor con otra fila, comparar una fila con filas adyacentes en una serie temporal, encontrar todos los pares de elementos que compartan una categoría.


Comparación de todos los tipos de unión

Tipo de unión Filas sin emparejar a la izquierda Filas sin emparejar a la derecha Cuándo utilizarla
INNER JOIN Excluidas Excluidas Solo quieres filas con una coincidencia en ambos lados
LEFT JOIN Incluidas (NULL) Excluidas Quieres todas las filas de la izquierda, con o sin coincidencia
RIGHT JOIN Excluidas Incluidas (NULL) Desea todas las filas de la derecha, con o sin coincidencia
FULL OUTER JOIN Incluidas (NULL) Incluidas (NULL) Desea todas las filas de ambas tablas
CROSS JOIN N/A (sin condición) N/A (sin condición) Necesitas todas las combinaciones de filas de ambas tablas
SELF JOIN Depende del tipo de unión utilizado Depende del tipo de unión utilizado Necesitas relacionar filas dentro de la misma tabla

Unión de más de dos tablas

Las consultas reales suelen unir tres, cuatro o más tablas. Cada unión adicional amplía el conjunto de resultados de la unión anterior. El orden es importante: cada JOIN opera sobre el resultado de todo lo que tiene a su izquierda.

SELECT
c.name,
o.order_id,
o.product,
p.category,
p.supplier
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
INNER JOIN productos p ON o.product_id = p.product_id
LEFT JOIN proveedores s ON p.supplier_id = s.supplier_id;

Algunos principios que permiten gestionar las uniones de varias tablas:

Empieza por la unión más selectiva. Si una unión reduce drásticamente el número de filas, colocarla en primer lugar hace que las uniones posteriores operen sobre menos filas. Esto puede tener importantes repercusiones en el rendimiento con tablas de gran tamaño.

Elige cuidadosamente los tipos de unión. Cada unión de una cadena es una decisión independiente. Podrías realizar una INNER JOIN entre «clientes» y «pedidos» (solo te interesan los clientes que han realizado un pedido), pero una LEFT JOIN entre «pedidos» y «envíos» (te interesan todos los pedidos, incluidos los que aún no se han enviado).

Utiliza alias de forma coherente. Con tres o más tablas, los nombres de las columnas pueden solaparse. Asigna siempre un alias a tus tablas y antepone un prefijo a cada referencia de columna. c.name no da lugar a ambigüedades; name en una unión de cuatro tablas supone un riesgo para el mantenimiento.

Comprueba el recuento de filas sobre la marcha. Al crear una consulta de unión compleja, añade cada tabla de forma incremental y comprueba el recuento de filas en cada paso. Un aumento inesperado del número de filas suele indicar que una condición de unión es incorrecta o falta.


Consideraciones sobre el rendimiento de las uniones

Las uniones son el punto en el que el rendimiento de SQL se mantiene o se viene abajo. Hay algunos principios que conviene comprender, independientemente del motor de base de datos que utilices.

Los índices en las columnas de unión son esenciales. Cuando realizas una unión por customer_id, la base de datos necesita buscar las filas coincidentes. Sin un índice, recorre toda la tabla en cada búsqueda. Con un índice, va directamente a las filas coincidentes. Para cualquier columna con la que realices uniones con frecuencia, asegúrate de que esté indexada: esta es la optimización de rendimiento más eficaz para consultas con muchas uniones.

Filtrar desde el principio reduce el coste de la unión. Colocar las condiciones WHERE lo antes posible —o utilizar subconsultas y CTE para filtrar previamente— hace que la unión se aplique a menos filas. Una unión entre 10 000 y 500 filas es mucho más económica que una unión entre 10 000 y 50 000 filas, incluso si el resultado filtrado final tiene el mismo tamaño.

EXPLAIN es tu aliado. Todos los principales motores de bases de datos admiten EXPLAIN (o EXPLAIN ANALYZE en PostgreSQL) para mostrar el plan de ejecución de la consulta. Si una consulta de unión es lenta, ejecuta primero EXPLAIN. Te indicará si se están utilizando índices, dónde se producen los escaneos secuenciales y cuáles son los recuentos estimados de filas en cada paso. Aprender a interpretar la salida de EXPLAIN es un factor que multiplica significativamente tu capacidad para optimizar el rendimiento de SQL.

Presta atención al «fan-out». Si el lado derecho de una unión tiene varias filas que coinciden con cada fila del lado izquierdo, el conjunto de resultados tendrá más filas que cualquiera de las tablas de entrada. Se trata de un comportamiento correcto, pero puede generar agregados inflados si no se tiene cuidado. COUNT(*) en un conjunto de resultados de una unión cuenta las filas unidas, no las filas originales del lado izquierdo. Utiliza COUNT(DISTINCT customer_id) o agrega los datos antes de realizar la unión cuando esto sea relevante.


Errores comunes y cómo evitarlos

Utilizar INNER JOIN cuando se necesita LEFT JOIN. La consulta produce resultados que parecen plausibles, pero faltan filas sin que se note. Pregúntate siempre: ¿deberían aparecer en mis resultados las filas sin coincidencia? Si la respuesta es sí, utiliza LEFT JOIN.

Filtrar por una columna NULL después de un LEFT JOIN. Si utilizas LEFT JOIN y luego añades WHERE o.status = 'shipped', has convertido efectivamente el LEFT JOIN en un INNER JOIN: se excluirán las filas en las que o.status sea NULL (es decir, las filas de la izquierda sin coincidencia). Filtra por columnas del lado derecho en la cláusula ON, no en la cláusula WHERE, si quieres conservar las filas de la izquierda sin coincidencia.

-- INCORRECTO: convierte el comportamiento de LEFT JOIN en el de INNER JOIN
SELECT c.name, o.order_id
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'shipped';  -- excluye las filas NULL

-- CORRECTO: conserva los clientes sin correspondencia
SELECT c.name, o.order_id
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
AND o.status = 'shipped';

Realizar una unión en una columna no única sin comprender las consecuencias. Si realizas una unión en una columna que tiene valores duplicados en el lado derecho, cada fila del lado izquierdo coincidirá con varias filas del lado derecho y el conjunto de resultados se multiplicará. A veces esto es lo que se busca; a menudo, no. Conoce la cardinalidad de tus datos antes de dar por sentado que una unión es 1:1.

Olvidarse de tratar los valores NULL en las agregaciones. SUM(o.amount) en el resultado de una LEFT JOIN ignorará correctamente los valores NULL, pero AVG(o.amount) también los ignorará, lo que significa que la media se calcula sobre los clientes que tienen pedidos, no sobre todos los clientes. COALESCE(o.amount, 0) suele ser el enfoque adecuado cuando los valores NULL deben tratarse como cero.


Referencia rápida: elegir la unión adecuada

Cuando te dispongas a escribir una consulta de unión, hazte estas preguntas en este orden:

  1. ¿Necesito las filas de la tabla de la izquierda aunque no tengan correspondencia en la de la derecha? Si la respuesta es sí → LEFT JOIN.
  2. ¿Necesito filas de la tabla de la derecha aunque no tengan coincidencia en la de la izquierda? Si la respuesta es sí → RIGHT JOIN (o cambia las tablas y utiliza LEFT JOIN).
  3. ¿Necesito filas sin coincidencia de ambos lados? Si la respuesta es sí → FULL OUTER JOIN.
  4. ¿Solo me interesan las filas que coinciden en ambos lados? Si la respuesta es sí → INNER JOIN.
  5. ¿Necesito todas las combinaciones de filas, independientemente de la relación? Si la respuesta es sí → CROSS JOIN (con precaución).
  6. ¿Estoy relacionando filas dentro de la misma tabla? Si la respuesta es sí → SELF JOIN utilizando cualquiera de los tipos anteriores.

Las uniones premian el razonamiento deliberado. El tipo que elijas es una declaración sobre lo que quieres que ocurra con las filas sin coincidencia. Toma la decisión correcta y el resto de la consulta surgirá de forma natural.