J'ai trois tables qui ressemblent à ceci:
PROD
Prod_ID|Desc ------------ P1|Foo1 P2|Foo2 P3|Foo3 P4|Foo4 ...
RAM
Ram_ID|Desc ------------ R1|Bar1 R2|Bar2 R3|Bar3 R4|Bar4 ...
PROD_RAM
Prod_ID|Ram_ID ------------ P1|R1 P2|R2 P3|R1 P3|R2 P3|R3 P4|R3 P5|R1 P5|R2 ...
Entre PROD et RAM, il existe une relation Many-To-Many décrite par la table PROD_RAM .
Étant donné un Ram_ID
défini comme (R1,R3)
je voudrais find tout le PROD
qui a exactement une ou la totalité de la RAM
de l'set donné.
Donné (R1,R3)
devrait returnner par exemple P1
, P4
et P5
; P3
ne doit pas être returnné car R1
et R3
mais aussi R2
.
Quelle est la requête la plus rapide pour get tous les PROD
qui ont exactement UN ou TOUS les Ram_ID
d'un set de RAM
donné?
MODIFIER:
La table PROD_RAM
peut contenir une relation plus grande que 1-> 3, donc les controls "codés en dur" pour count = 1 OR = 2 ne sont pas une solution viable.
Une autre solution que vous pourriez essayer pour la vitesse serait comme ça
;WITH CANDIDATES AS ( SELECT pr1.Prod_ID , pr2.Ram_ID FROM PROD_RAM pr1 INNER JOIN PROD_RAM pr2 ON pr2.Prod_ID = pr1.Prod_ID WHERE pr1.Ram_ID IN ('R1', 'R3') ) SELECT * FROM CANDIDATES WHERE CANDIDATES.Prod_ID NOT IN ( SELECT Prod_ID FROM CANDIDATES WHERE Ram_ID NOT IN ('R1', 'R3') )
ou si vous n'aimez pas répéter les conditions définies
;WITH SUBSET (Ram_ID) AS ( SELECT 'R1' UNION ALL SELECT 'R3' ) , CANDIDATES AS ( SELECT pr1.Prod_ID , pr2.Ram_ID FROM PROD_RAM pr1 INNER JOIN PROD_RAM pr2 ON pr2.Prod_ID = pr1.Prod_ID INNER JOIN SUBSET s ON s.Ram_ID = pr1.Ram_ID ) , EXCLUDES AS ( SELECT Prod_ID FROM CANDIDATES LEFT OUTER JOIN SUBSET s ON s.Ram_ID = CANDIDATES.Ram_ID WHERE s.Ram_ID IS NULL ) SELECT * FROM CANDIDATES LEFT OUTER JOIN EXCLUDES ON EXCLUDES.Prod_ID = CANDIDATES.Prod_ID WHERE EXCLUDES.Prod_ID IS NULL
Une façon de le faire serait quelque chose comme:
SELECT PROD.Prod_ID FROM PROD WHERE (SELECT COUNT(*) FROM PROD_RAM WHERE PROD_RAM.Prod_ID = PROD.Prod_ID) > 0 AND (SELECT COUNT(*) FROM PROD_RAM WHERE PROD_RAM.Prod_ID = PROD.Prod_ID AND PROD.Ram_ID <> IFNULL((SELECT TOP 1 Ram_ID FROM PROD_RAM WHERE PROD_RAM.Prod_ID = PROD.Prod_ID),0)) = 0
SELECT Prod_ID FROM ( SELECT Prod_ID , COUNT(*) AS cntAll , COUNT( CASE WHEN Ram_ID IN (1,3) THEN 1 ELSE NULL END ) AS cntGood FROM PROD_RAM GROUP BY Prod_ID ) AS grp WHERE cntAll = cntGood AND ( cntGood = 1 OR cntGood = 2 --- number of items in list (1,3) )
Pas du tout certain si c'est le moyen le plus rapide. Vous devrez essayer différentes façons d'écrire cette requête (en utilisant JOIN
et NOT EXISTS
) et tester la vitesse.