queryLab · software_de_entrenamiento en espera
Nivel 2 · Intermedio · SQL · DQL

[SQL 07] Combinar tablas con JOIN

INNER, LEFT, RIGHT, FULL, CROSS, self-join y anti-join.
0 / 8 retos resueltos 📘 Clases 9 y 11 · INNER / LEFT / RIGHT / FULL JOIN y alias
Al terminar esta práctica podrás…
  • Unir dos o más tablas por sus claves con INNER JOIN … ON y alias.
  • Conservar filas sin pareja con LEFT JOIN y detectar «huérfanos» (anti-join).
  • Relacionar una tabla consigo misma (self-join) para jerarquías jefe → empleado.
  • Combinar JOIN con WHERE, GROUP BY y HAVING en informes.

Un modelo normalizado reparte la información en varias tablas. El JOIN las vuelve a combinar siguiendo las claves: normalmente la FK de una tabla con la PK de otra (employees.department_id = departments.department_id).

  • INNER JOIN (o solo JOIN): solo las filas que tienen pareja en ambas tablas.
  • LEFT JOIN: todas las filas de la tabla izquierda; si no hay pareja, las columnas de la derecha quedan en NULL.
  • RIGHT JOIN: lo mismo, conservando la tabla derecha. FULL JOIN: conserva ambas.
  • CROSS JOIN: todas las combinaciones posibles (producto cartesiano).

Usa alias cortos (e, d, l) y antepónlos a las columnas: evita la ambigüedad cuando dos tablas tienen columnas con el mismo nombre.

Sintaxis
SELECT e.col, d.col
FROM tabla1 e
[INNER | LEFT | RIGHT | FULL] JOIN tabla2 d
  ON e.fk = d.pk
WHERE …;
INNER JOIN
Intersección: solo filas con coincidencia.
LEFT JOIN
Todo lo de la izquierda + lo que coincida de la derecha.
Anti-join
LEFT JOIN … WHERE derecha.pk IS NULL: filas sin pareja.
Self-join
La misma tabla dos veces con alias distintos (empleado / jefe).
Varias tablas
Encadena JOIN: employees → departments → locations → countries.
JOIN implícito
FROM a, b WHERE a.x = b.x: sintaxis antigua, mejor evitarla.
SQLite 3.39+
Soporta INNER, LEFT, RIGHT, FULL y CROSS JOIN
MySQL
Sin FULL JOIN: se emula con LEFT … UNION … RIGHT
Oracle
Todos los JOIN ANSI; sintaxis antigua (+) para outer join

1 · Ejemplos guiados · ejecuta y modifica cada bloque

01INNER JOIN con alias
Cada empleado con el nombre de su departamento (clase 11).
sql-joins.sql
Presiona «ejecutar» para ver el resultado.
02Cuatro tablas encadenadas
Empleado → departamento → ubicación → país.
sql-joins.sql
Presiona «ejecutar» para ver el resultado.
03LEFT JOIN: conservar las filas sin pareja
Todas las ciudades, tengan o no departamentos. Las que no tienen muestran NULL.
sql-joins.sql
Presiona «ejecutar» para ver el resultado.
04Anti-join: ubicaciones sin departamentos
Agregando WHERE d.department_id IS NULL nos quedamos solo con las filas sin pareja (técnica de la guía de ejercicios: «proveedores sin artículos»).
sql-joins.sql
Presiona «ejecutar» para ver el resultado.
05Self-join: empleado y su jefe
employees aparece dos veces: e (empleado) y m (jefe). Con LEFT JOIN no perdemos al presidente, que no tiene jefe.
sql-joins.sql
Presiona «ejecutar» para ver el resultado.
06JOIN + GROUP BY + HAVING (clase 9)
Total de salarios por título de cargo, solo los que superan 100000.
sql-joins.sql
Presiona «ejecutar» para ver el resultado.
07FULL JOIN emulado con UNION
Donde no existe FULL JOIN (MySQL), se combina un LEFT y un RIGHT (escrito como LEFT invertido) con UNION.
sql-joins.sql
Presiona «ejecutar» para ver el resultado.

⚠ Errores frecuentes

  • Olvidar el ON (o ponerlo mal) genera un producto cartesiano: 102 × 11 = 1122 filas.
  • No usar alias y escribir department_id a secas cuando existe en ambas tablas: error «ambiguous column name».
  • Hacer un LEFT JOIN y luego filtrar la tabla derecha en el WHERE (WHERE d.department_name = 'IT'): lo convierte en INNER. Pon esa condición en el ON.
  • Contar con COUNT(*) después de un LEFT JOIN: cuenta también las filas sin pareja. Usa COUNT(columna_de_la_derecha).

2 · Retos con corrección automática

Escribe tu solución y pulsa comprobar (Ctrl + Enter). Tu consulta y la solución se ejecutan en bases limpias y se comparan los resultados: no importan los nombres de las columnas, sí los datos (y el orden, cuando el reto lo pide). Si te atascas, usa la pista o mira el resultado esperado.

3 · Preguntas tipo solemne

1. ¿Qué JOIN devuelve todos los estudiantes, aunque no estén inscritos en ningún curso (clase 11)?
2. ¿Qué devuelve esta consulta?
SELECT p.nombre
FROM proveedor p
LEFT JOIN articulo a ON p.id = a.proveedor_id
WHERE a.id IS NULL;
3. En una relación 1:N clientes–pedidos, un cliente con 3 pedidos aparece en un INNER JOIN…
4. ¿Qué tipo de JOIN conviene para listar cada empleado junto a su jefe en la misma tabla?