Usando la combinación interna DISTINCT en SQL
-
03-07-2019 - |
Pregunta
Tengo tres tablas, A, B, C, donde A es de muchos a uno B, y B es de muchos a uno C. Me gustaría obtener una lista de todas las C en A
Mis tablas son algo como esto: A [id, valueA, lookupB], B [id, valueB, lookupC], C [id, valueC]. He escrito una consulta con dos SELECTs anidados, pero me pregunto si es posible hacer INNER JOIN con DISTINCT de alguna manera.
SELECT valueC
FROM C
INNER JOIN
(
SELECT DISTINCT lookupC
FROM B INNER JOIN
(
SELECT DISTINCT lookupB
FROM A
)
A2 ON B.id = A2.lookupB
)
B2 ON C.id = B2.lookupC
EDITAR: Las tablas son bastante grandes, A es de 500k filas, B es de 10k filas y C es de 100 filas, por lo que hay una gran cantidad de información innecesaria si hago una combinación interna básica y uso DISTINCT al final, como este:
SELECT DISTINCT valueC
FROM
C INNER JOIN B on C.id = B.lookupB
INNER JOIN A on B.id = A.lookupB
Esto es muy, muy lento (las magnitudes son más lentas que el SELECT anidado que hago arriba.
Solución
Hice una prueba en MS SQL 2005 usando las siguientes tablas: A 400K filas, B 26K filas y C 450 filas.
El plan de consulta estimado indicó que la combinación interna básica sería 3 veces más lenta que las consultas secundarias anidadas; sin embargo, al ejecutar la consulta, la combinación interna básica era dos veces más rápida que las consultas anidadas. 297 ms en hardware de servidor muy mínimo.
¿Qué base de datos está utilizando y qué horas está viendo? Estoy pensando que si está viendo un rendimiento bajo, entonces probablemente sea un problema de índice.
Otros consejos
Creo que tus relaciones 1: m ya deberían crear, de forma implícita, DISTINCT JOINs.
Pero, si tu meta es solo C en cada A, puede ser más fácil usar DISTINCT en la consulta más externa.
SELECT DISTINCT a.valueA, c.valueC
FROM C
INNER JOIN B ON B.lookupC = C.id
INNER JOIN A ON A.lookupB = B.id
ORDER BY a.valueA, c.valueC
SELECT DISTINCT C.valueC
FROM C
LEFT JOIN B ON C.id = B.lookupC
LEFT JOIN A ON B.id = A.lookupB
WHERE C.id IS NOT NULL
No veo una buena razón por la que quieres limitar los conjuntos de resultados de A y B porque lo que quieres es una lista de todas las C a las que hace referencia A. Hice una diferencia en C.valueC porque Supuse que querías una lista única de C's.
EDIT : estoy de acuerdo con tu argumento. Incluso si su solución se ve un poco anidada, parece ser la mejor y más rápida manera de utilizar su conocimiento de los datos y reducir los conjuntos de resultados.
No hay una construcción de unión distinta que puedas usar, así que quédate con lo que ya tienes :)
¿Esto es lo que quieres decir?
SELECT DISTINCT C.valueC
FROM
C
INNER JOIN B ON C.id = B.lookupC
INNER JOIN A ON B.id = A.lookupB