SQLJOININNER JOINtutorial

¿Qué es INNER JOIN en SQL? Unir tablas para principiantes

INNER JOIN combina filas de dos tablas por una clave compartida. El JOIN más sencillo y más común. Cubrimos la sintaxis, la cláusula ON, las uniones de varias tablas, los errores comunes y tres ejercicios prácticos.

7 min de lecturaSQL · JOIN · INNER JOIN · tutorial · beginner

INNER JOIN (o simplemente JOIN) es el comando de SQL para combinar dos tablas por una clave compartida. El tipo de JOIN más sencillo y más común — con las bases de datos relacionales no llegarás lejos sin él.

Una analogía rápida. Tienes dos tablas:

  • users — usuarios (id, name)
  • orders — pedidos (id, user_id, amount)

En orders no hay nombre del comprador — solo user_id. Para obtener parejas de «nombre del comprador + importe del pedido», tienes que volver a pegar estas tablas por una clave común — users.id coincide con orders.user_id. Ese pegado es INNER JOIN.

Por qué importa JOIN

Una base de datos normal reparte los datos entre tablas para evitar la duplicación. El nombre del usuario vive solo en users; orders referencia al usuario mediante user_id. Esto se llama normalización.

Cuando necesitas mostrar «nombre + pedido», tienes que volver a ensamblar los datos — para eso está JOIN. Es uno de los temas más importantes de SQL — sin JOIN no puedes escribir ni una sola consulta del mundo real.

Sintaxis básica

SELECT columns
FROM table_A
INNER JOIN table_B
  ON table_A.key = table_B.key;

La palabra INNER es opcional — JOIN sin prefijo significa INNER JOIN. La mayoría del código pone solo JOIN.

Ejemplo: una tienda

Tabla users:

idnameemail
1Annaanna@example.com
2Borisbob@example.com
3Veravera@example.com
4Grishagrisha@example.com

Tabla orders:

iduser_idamountcreated_at
1015002024-03-01
11115002024-03-05
1222002024-03-07
13530002024-03-10

Consulta — unir y mostrar el nombre del comprador con el importe:

SELECT users.name, orders.amount, orders.created_at
FROM users
INNER JOIN orders
  ON users.id = orders.user_id;

Resultado:

nameamountcreated_at
Anna5002024-03-01
Anna15002024-03-05
Boris2002024-03-07

Qué pasó:

  • Cada fila de users se emparejó con cada fila de orders donde users.id = orders.user_id.
  • Anna tiene dos pedidos → dos filas en el resultado, con el nombre duplicado.
  • Boris tiene un pedido → una fila.
  • Vera y Grisha no están — no tienen pedidos. Ese es el rasgo del INNER JOIN: solo parejas con coincidencia en ambas tablas.
  • El pedido #13 no estáuser_id = 5 no existe en users. A veces ocurre, p. ej. el usuario se borró pero el pedido se quedó.

Si también quieres los usuarios sin pedidos, eso es LEFT JOIN (artículo aparte).

Alias — nombres cortos de tabla

Escribir users.name, orders.amount cada vez es largo. El código del mundo real usa alias:

SELECT u.name, o.amount, o.created_at
FROM users u
INNER JOIN orders o
  ON u.id = o.user_id;

users u significa «dale a la tabla users el alias u». No cambia la lógica — solo es más corto. En consultas grandes con tres o cinco tablas, las consultas sin alias son ilegibles.

Nota: los alias se vuelven obligatorios si ambas tablas tienen una columna con el mismo nombre. De lo contrario la base de datos no puede saber a qué id te refieres.

Unir tres o más tablas

Los JOIN se encadenan: A JOIN B JOIN C. Añade una tabla products:

idnameprice
100Bosch kettle49
101iPhone 15999
102Book "Clean Code"22

Y amplía orders con product_id:

iduser_idproduct_idamount
10110049
11110222
12210049

Consulta — quién compró qué:

SELECT u.name AS buyer, p.name AS product, o.amount
FROM users u
INNER JOIN orders o   ON u.id = o.user_id
INNER JOIN products p ON p.id = o.product_id;

Resultado:

buyerproductamount
AnnaBosch kettle49
AnnaBook "Clean Code"22
BorisBosch kettle49

Cómo funciona:

  1. La base de datos primero une users y orders por user_id.
  2. Luego el resultado se une con products por product_id.
  3. La salida conserva solo las filas donde ambas uniones coincidieron.

Estas cadenas pueden ser tan largas como necesites. «Usuarios, sus pedidos, los productos de esos pedidos, las categorías de los productos y las tiendas» — eso son cinco JOIN seguidos.

JOIN con WHERE

JOIN suele ir con WHERE — JOIN pega las tablas, WHERE filtra el resultado. P. ej. los pedidos de Anna por encima de 1000:

SELECT u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.name = 'Anna'
  AND o.amount > 1000;

Una combinación extremadamente común — casi cualquier consulta de negocio es «une las tablas + filtra con WHERE + tal vez agrega».

INNER JOIN es la intersección

En términos de teoría de conjuntos: INNER JOIN es la intersección de dos tablas por una clave. Solo las filas presentes en ambas entran.

users       orders
  ┌──┐      ┌──┐
  │  │      │  │
  │ ●│ ←  → │● │  ← parejas: solo estas acaban en el resultado
  │  │      │  │
  └──┘      └──┘

Un usuario sin pedidos — no está en el resultado. Un pedido sin usuario (clave foránea rota) — tampoco está en el resultado.

Ejemplo más grande: una biblioteca

books:

idtitleauthor_id
1War and Peace10
2Anna Karenina10
3Crime and Punishment11
4The Idiot11
5(orphan — author not in DB)99

authors:

idfull_namecountry
10Leo TolstoyRussia
11Fyodor DostoevskyRussia
12Erich Maria RemarqueGermany

Consulta — cada libro con el nombre del autor y el país:

SELECT b.title, a.full_name AS author, a.country
FROM books b
JOIN authors a ON a.id = b.author_id
ORDER BY a.full_name, b.title;

Resultado:

titleauthorcountry
Anna KareninaLeo TolstoyRussia
War and PeaceLeo TolstoyRussia
Crime and PunishmentFyodor DostoevskyRussia
The IdiotFyodor DostoevskyRussia

El libro huérfano desapareció — author_id = 99 no está en authors. Remarque desapareció — tiene cero libros en nuestra books. INNER JOIN descartó ambos.

Errores habituales de principiante

1. Olvidar la cláusula ON. Escribir JOIN orders sin ON — la mayoría de las bases de datos o dan error o recurren a un CROSS JOIN (producto cartesiano, cada fila por cada fila). O un error o una consulta muy lenta.

2. Columnas equivocadas en ON. ON u.id = o.id en lugar de ON u.id = o.user_id es una errata clásica. La consulta no se romperá — devolverá un sinsentido (el usuario #5 emparejado con el pedido #5, lo cual no tiene significado).

3. Nombres de columna ambiguos. Si tanto users como orders tienen id, y escribes SELECT id, name FROM users JOIN orders ON …, obtienes «la referencia a la columna "id" es ambigua». Usa users.id o alias.

4. Filas duplicadas en el resultado. Si un usuario tiene 5 pedidos, el resultado tiene 5 filas con el nombre de ese usuario repetido. No es un error — así funciona JOIN. ¿Quieres usuarios únicos? Envuélvelo en SELECT DISTINCT u.name o combínalo con GROUP BY.

5. Pensar que JOIN en sí es lento. Los JOIN son rápidos cuando hay índices en las columnas de unión. Por eso las columnas de clave foránea (user_id y similares) siempre están indexadas en producción.

6. Uniones antiguas con coma. Técnicamente puedes escribir FROM users, orders WHERE users.id = orders.user_id. No lo hagas. La sintaxis moderna JOIN ... ON ... se lee mejor y separa con claridad la unión del filtrado.

Resumen rápido

  • INNER JOIN combina dos tablas por una clave compartida.
  • Solo las parejas con coincidencia en ambas tablas entran en el resultado.
  • La condición de unión va después de ON.
  • La palabra INNER es opcional; la gente escribe simplemente JOIN.
  • Puedes encadenar muchos JOIN (las consultas de tres y cinco tablas son normales).
  • Usa alias (users u) para mantener las cosas legibles.
  • Si también quieres usuarios sin pedidos, eso es LEFT JOIN, un escenario distinto.

Pruébalo tú

Sobre las tablas users y orders de arriba:

  1. Lista parejas de nombre del comprador e importe, ordenadas por importe descendente.
  2. Encuentra todos los usuarios que hicieron un pedido en marzo de 2024.
  3. Cuenta el importe total de pedidos por usuario (combinación JOIN + GROUP BY + SUM).

Cuando JOIN te encaja, es un momento liberador al aprender SQL. Antes — puedes leer una tabla. Después — los datos del mundo real se abren del todo.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador