El síntoma: esperabas una fila y aparecen varias
Un JOIN no “duplica” filas de forma arbitraria. Produce todas las parejas que cumplen la condición de unión. Si un pedido tiene tres líneas en detalle_pedido, ese pedido puede aparecer tres veces al unir ambas tablas.
La pregunta correcta no es “¿cómo quito duplicados?”, sino “¿qué granularidad quiero en el resultado y cuántas coincidencias tiene cada clave?”.
Ejemplo: dos pedidos se convierten en cinco filas
Los pedidos 101 y 106 son dos pedidos distintos, pero tienen cinco líneas de detalle en total:
SELECT p.id AS pedido_id,
c.nombre AS cliente,
dp.producto_id
FROM pedidos AS p
JOIN clientes AS c
ON c.id = p.cliente_id
JOIN detalle_pedido AS dp
ON dp.pedido_id = p.id
WHERE p.id IN (101, 106)
ORDER BY p.id, dp.id;| pedido_id | cliente | producto_id |
|---|---|---|
| 101 | Ana Torres | 1 |
| 101 | Ana Torres | 2 |
| 101 | Ana Torres | 5 |
| 106 | Sara Gómez | 4 |
| 106 | Sara Gómez | 8 |
El resultado es correcto si quieres una fila por línea de detalle. Es incorrecto únicamente si tu intención era una fila por pedido.
Diagnóstico en tres preguntas
- ¿Cuál es la unidad del resultado? Pedido, cliente, producto, línea de pedido… Escríbela con palabras.
- ¿La clave de unión es única en cada lado?
pedidos.ides única, perodetalle_pedido.pedido_idpuede repetirse. - ¿Cuántas coincidencias tiene cada clave? Cuenta antes de intentar “limpiar” el resultado.
SELECT pedido_id,
COUNT(*) AS lineas
FROM detalle_pedido
GROUP BY pedido_id
HAVING COUNT(*) > 1
ORDER BY lineas DESC, pedido_id;| pedido_id | lineas |
|---|---|
| 101 | 3 |
| 113 | 3 |
| 106 | 2 |
| 107 | 2 |
| 110 | 2 |
| 114 | 2 |
| 117 | 2 |
La solución depende de la intención
Si quieres una fila por pedido, agrega las líneas
SELECT p.id AS pedido_id,
c.nombre AS cliente,
SUM(dp.cantidad * dp.precio_unitario) AS total_lineas
FROM pedidos AS p
JOIN clientes AS c
ON c.id = p.cliente_id
JOIN detalle_pedido AS dp
ON dp.pedido_id = p.id
WHERE p.id IN (101, 106)
GROUP BY p.id, c.nombre
ORDER BY p.id;| pedido_id | cliente | total_lineas |
|---|---|---|
| 101 | Ana Torres | 128,40 |
| 106 | Sara Gómez | 1088,00 |
Si solo quieres saber si existe una coincidencia, no necesitas traer todas
En algunos problemas, EXISTS expresa mejor la intención que unir una tabla solo para comprobar presencia. Eso evita introducir varias filas del lado dependiente en el resultado principal.
Por qué DISTINCT no es el primer remedio
Añadir DISTINCT sin diagnosticar la relación
DISTINCT elimina filas idénticas en las columnas seleccionadas. Puede ocultar una multiplicación, pero no cambia la cardinalidad de la relación. Si más adelante añades una columna de detalle, las filas volverán a diferenciarse. Decide primero qué representa una fila.
Práctica correctiva
Una fila por pedido con número de líneas
Devuelve los pedidos 101 y 106 con el nombre del cliente y el número de líneas de detalle. El resultado debe tener exactamente dos filas.
COUNT(*).Solución razonada
SELECT p.id AS pedido_id,
c.nombre AS cliente,
COUNT(*) AS lineas
FROM pedidos AS p
JOIN clientes AS c
ON c.id = p.cliente_id
JOIN detalle_pedido AS dp
ON dp.pedido_id = p.id
WHERE p.id IN (101, 106)
GROUP BY p.id, c.nombre
ORDER BY p.id;El JOIN sigue produciendo una fila por detalle internamente, pero GROUP BY vuelve a la granularidad de pedido y COUNT(*) resume cuántas líneas tiene cada uno: 101 tiene 3 y 106 tiene 2.
Qué debes recordar
- Un JOIN produce una fila por combinación que cumple
ON. - Una relación uno-a-muchos aumenta naturalmente el número de filas.
- Define la granularidad deseada antes de corregir.
- Cuenta coincidencias y usa agregación o
EXISTScuando expresen mejor la intención. - No uses
DISTINCTcomo parche automático.