Evitar datos repetidos si no se puede usar distinct

A veces ocurre que en el resultado de una consulta obtenemos datos repetidos que surgen del emparejamiento de tuplas de dos tablas (o de la misma tabla si se hace un auto-join). No me refiero a tuplas repetidas (que se evitarían con un distinct) sino a valores repetidos en diferentes columnas del resultado. Pongamos un ejemplo.

Supongamos la siguiente tabla de personas:

+------+----------+
| DNI  | nombre   |
+------+----------+
| 1111 | Ana Abad |
| 2222 | Bea Bez  |
| 3333 | Ana Abad |
+------+----------+

Supongamos que queremos saber las parejas de DNI de personas que se llaman igual, excluyendo los emparejamientos de una persona consigo misma.

Para ello planteamos una consulta (de tipo auto-join) como la siguiente:

MEJORABLE
select P1.nombre, P1.DNI, P2.DNI
from Persona P1 
     join Persona P2 on P1.nombre = P2.nombre 
                        and P1.DNI <> P2.DNI;

Que arroja como resultado lo siguiente:

+----------+------+------+
| nombre   | DNI  | DNI  |
+----------+------+------+
| Ana Abad | 3333 | 1111 |
| Ana Abad | 1111 | 3333 |
+----------+------+------+

Como ves, aunque las dos filas son diferentes (esto no se puede corregir con distinct), tenemos en ellas la misma información.

¿Cómo podemos evitar esta duplicación? El truco es muy sencillo. Se trata de no usar la diferencia (<> o !=) y usar una comparación de orden (> o <):

BIEN
select P1.nombre, P1.DNI, P2.DNI
from Persona P1 
     join Persona P2 on P1.nombre = P2.nombre 
                        and P1.DNI < P2.DNI;

Otro ejemplo, no tan directo.

Supongamos la siguiente tabla de artículos, en la que se aprecia que hay artículos que se venden junto con otros:

+----+---------+------------+
| id | nombre  | vendidoCon |
+----+---------+------------+
|  1 | Móvil 1 |       NULL |
|  2 | Móvil 2 |          3 |
|  3 | Funda   |          2 |
|  4 | Tablet  |       NULL |
+----+---------+------------+

Supongamos que queremos saber los artículos que se venden emparejados.

Para ello planteamos una consulta (de tipo auto-join) como la siguiente:

MEJORABLE
select A1.nombre, A2.nombre
from Articulo A1 
     join Articulo A2 on A1.vendidoCon = A2.id;

Que arroja como resultado lo siguiente:

+---------+---------+
| nombre  | nombre  |
+---------+---------+
| Móvil 2 | Funda   |
| Funda   | Móvil 2 |
+---------+---------+

De nuevo vemos filas con la misma información. Para evitarlo usaremos el mismo truco. En este caso añadiremos una condición adicional para exigir que el primer artículo tenga un id menor que el segundo (o viceversa). Así evitamos que aparezcan ambos:

BIEN
select A1.nombre, A2.nombre
from Articulo A1 
     join Articulo A2 on A1.vendidoCon = A2.id
where A1.id < A2.id;

No hay comentarios:

Publicar un comentario