DBA Junior Ciberecus MX
Temas · Capítulo 2 · PF-009

Tema 9: JOIN: unir tablas como un detective une pistas

Identificador: PF-009 | XP: 200 | Insignia: 🥇 Oro | Tier: Aprendiz
Tiempo estimado: 90-120 min | Pre-requisitos: PF-007, PF-008

🖼️ Imagen de inicio del tema

Cartoon Tema 9 - Moka con palapas uniendo altépetl

[Moka como tlacuilo con códigos que se conectan entre altépetl (clientes, productos, pedidos). Sofía con lupa detective, Don Carlos observando, Citlalli explicando el patrón de cruce.]


🎯 Aprenderás

    INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN. Cómo unir 2 o más tablas con la cláusula `ON`. Cuándo usar cada tipo de JOIN según el caso de negocio. Los errores típicos de JOIN (producto cartesiano, ON mal puesto).

🏛️ Visión mexica — Por Citlalli

Citlalli: "El tlatoani mexica recibía tributos de 371 altépetl. Para entender el flujo completo, el tlacuilo NO leía cada codex por separado: tenía que CRUZAR la información. Por ejemplo, '¿cuánto cacao llegó de cada altépetl en cada año?'. Eso requería unir los codex de tributos con los codex de calendario. Hoy lo llamamos JOIN.

El poder del JOIN es el mismo que el del tlacuilo: convertir datos aislados en conocimiento conectado. Una tabla de clientes sola no te dice qué compraron. Una tabla de pedidos sola no te dice quién compró. Pero al unirlas con JOIN, tienes 'qué compró cada cliente'. Esa es la magia de las bases de datos relacionales."


📚 Bloque 1: El concepto de JOIN

Tienes dos tablas. Cada una tiene información diferente pero RELACIONADA. JOIN te permite combinarlas en una sola consulta.

Tablas del ejemplo:

  • `clientes` (id, nombre, ciudad)
  • `pedidos` (id, cliente_id, fecha_pedido, total)
Si quieres "los nombres de los clientes que tienen pedidos", necesitas datos de AMBAS tablas. JOIN los une.

SELECT clientes.nombre, pedidos.fecha_pedido, pedidos.total
FROM clientes
INNER JOIN pedidos ON clientes.id = pedidos.cliente_id;

Don Carlos: "La cláusula `ON` es CLAVE. Le dice a la base de datos: 'la fila de la tabla A se conecta con la fila de la tabla B cuando esta condición es verdadera'. Sin el ON correcto, JOIN no une nada útil."


📚 Bloque 2: Los 4 tipos de JOIN principales

INNER JOIN — devuelve solo las filas que tienen coincidencia en AMBAS tablas. Es el más común.

-- Solo clientes que TIENEN pedidos
SELECT c.nombre, p.fecha_pedido, p.total
FROM clientes c
INNER JOIN pedidos p ON c.id = p.cliente_id;

LEFT JOIN — devuelve TODAS las filas de la tabla izquierda, y los datos de la derecha si hay coincidencia (NULL si no).

-- TODOS los clientes, y sus pedidos si los tienen
SELECT c.nombre, p.fecha_pedido, p.total
FROM clientes c
LEFT JOIN pedidos p ON c.id = p.cliente_id
ORDER BY c.nombre;

Útil para: encontrar clientes que NO tienen pedidos (los NULL en `p.fecha_pedido`).

RIGHT JOIN — lo opuesto de LEFT JOIN. Menos común.

FULL OUTER JOIN — devuelve todas las filas de ambas tablas, con NULL donde no hay coincidencia. Soportado en PostgreSQL pero NO en MySQL directamente (requiere UNION).


📚 Bloque 3: JOIN con 3 o más tablas

Para queries reales, unirás 3+ tablas frecuentemente.

-- Quién compró qué (cliente + producto + pedido)
SELECT c.nombre AS cliente, p.nombre AS producto, pi.cantidad, pi.precio_unitario
FROM clientes c
INNER JOIN pedidos pe ON c.id = pe.cliente_id
INNER JOIN pedido_items pi ON pe.id = pi.pedido_id
INNER JOIN productos p ON pi.producto_id = p.id
ORDER BY c.nombre;

📚 Bloque 4: Errores típicos

    Olvidar el ON: produce un producto cartesiano (todas las combinaciones). Con 50 clientes × 110 pedidos = 5500 filas sin sentido. ON con condición incorrecta: une filas que no deberían estar juntas. Confundir LEFT JOIN con INNER JOIN: clientes sin pedidos desaparecen con INNER. Usar WHERE en vez de ON: la condición WHERE se aplica DESPUÉS del JOIN, lo cual puede dar resultados diferentes.
Moka: "Si tu query con JOIN devuelve 100 veces más filas de las esperadas, casi siempre es producto cartesiano. Revisa tu ON."


🤖 AI Mission

Pídele a la IA: "Explícame con un ejemplo de la vida real por qué INNER JOIN puede dejarte sin clientes 'huérfanos', y cómo LEFT JOIN los rescata."


⚠️ Errores típicos

    Producto cartesiano por olvidar ON. Usar WHERE en lugar de ON. Asumir el tipo de JOIN incorrecto. JOIN sobre tablas enormes sin índices (rendimiento).

🧪 LAB 9.1 — "Las 7 queries con JOIN de Tienda Tlalli"

Query 1: nombres de clientes con sus pedidos (solo los que tienen).

SELECT c.nombre, p.fecha_pedido, p.total
FROM clientes c
INNER JOIN pedidos p ON c.id = p.cliente_id;

Query 2: TODOS los clientes y sus pedidos (incluyendo los que no tienen).

SELECT c.nombre, p.fecha_pedido, p.total
FROM clientes c
LEFT JOIN pedidos p ON c.id = p.cliente_id
ORDER BY c.nombre;

Query 3: clientes de Monterrey que NO tienen pedidos.

SELECT c.nombre
FROM clientes c
LEFT JOIN pedidos p ON c.id = p.cliente_id
WHERE c.ciudad = 'Monterrey' AND p.id IS NULL;

Query 4: nombre del cliente, nombre del producto, cantidad, total de cada pedido.

SELECT c.nombre AS cliente, pr.nombre AS producto, pi.cantidad, pi.precio_unitario
FROM clientes c
INNER JOIN pedidos pe ON c.id = pe.cliente_id
INNER JOIN pedido_items pi ON pe.id = pi.pedido_id
INNER JOIN productos pr ON pi.producto_id = pr.id
ORDER BY c.nombre;

Query 5: total gastado por cada cliente.

SELECT c.nombre, SUM(pe.total) AS total_gastado
FROM clientes c
INNER JOIN pedidos pe ON c.id = pe.cliente_id
GROUP BY c.nombre
ORDER BY total_gastado DESC;

Query 6: productos vendidos más de 5 veces.

SELECT pr.nombre, SUM(pi.cantidad) AS total_vendido
FROM productos pr
INNER JOIN pedido_items pi ON pr.id = pi.producto_id
GROUP BY pr.nombre
HAVING SUM(pi.cantidad) > 5
ORDER BY total_vendido DESC;

Query 7: clientes que compraron productos de la categoría "Mesoamérica" (id=19).

SELECT DISTINCT c.nombre
FROM clientes c
INNER JOIN pedidos pe ON c.id = pe.cliente_id
INNER JOIN pedido_items pi ON pe.id = pi.pedido_id
INNER JOIN productos pr ON pi.producto_id = pr.id
WHERE pr.categoria_id = 19
ORDER BY c.nombre;


📝 Quest 9 (10 MC + 3 abiertas)

    ¿Qué hace INNER JOIN? A) Une solo filas con coincidencia. B) Une todas. C) Solo izquierda. D) Solo derecha. ¿Qué pasa si olvidas el ON? A) Error. B) Producto cartesiano. C) Nada. D) Solo la primera fila. ¿Qué muestra LEFT JOIN? A) Solo izquierda. B) Solo derecha. C) Solo coincidencia. D) Solo NULL. ¿Para qué sirve `tabla.campo`? A) Decoración. B) Desambiguar columnas con mismo nombre en diferentes tablas. C) Error de sintaxis. D) Comentario. ¿Qué hace un JOIN de 3 tablas? A) Conecta 3 tablas según 2 condiciones ON. B) Une las 3 como un cubo. C) Solo funciona con 2. D) No existe. ¿Por qué usar `c` y `p` como alias? A) Moda. B) Reducir escritura y hacer código más legible. C) Obligatorio. D) Reduce rendimiento. ¿Cuál es el primer paso para diagnosticar un JOIN lento? A) Optimizar todo. B) Revisar índices. C) Cambiar el motor. D) Complicar la query. ¿Qué cliente en CDMX NO ha comprado? (análoga a Query 3, con ciudad = 'Ciudad de México') ¿Qué hace `LEFT JOIN` si no hay coincidencia? A) Fila no aparece. B) Aparece con NULL en campos de la derecha. C) Error. D) Aparece duplicada. ¿Cuántos JOINs para unir 4 tablas? A) 2. B) 3. C) 4. D) 1.
Abiertas:
    Explica con un ejemplo el producto cartesiano. ¿Cuándo LEFT JOIN vs INNER JOIN? Diseña una query con 3 JOINs que responda una pregunta de negocio.

✅ Respuestas

1-A, 2-B, 3-A, 4-B, 5-A, 6-B, 7-B, 8-variará, 9-B, 10-B.


🏛️ Tras las huellas — Por Citlalli

"El tlatoani recibía tributos de 371 altépetl. Para entender el flujo completo, el tlacuilo NO leía cada codex por separado: tenía que CRUZAR la información. Eso es JOIN.

En Mesoamérica, los kipus (nudos en cuerdas) eran una forma de JOIN visual: cada color de cuerda representaba un tipo de tributo, y los nudos a lo largo de la misma cuerda conectaban los registros por altépetl. Es un JOIN analógico de 5,000 años de antigüedad."


📓 Cierre

1. Lo más útil fue:
2. El error que más me asustó fue:
3. Una query que quiero memorizar:
4. Cómo voy a aplicar LEFT JOIN en mi trabajo:

🚀 ¿Qué sigue?

Tema 10 — Funciones de agregación y GROUP BY: el poder de resumir.