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.

¿Fue útil?

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top