在多对多关系中查找具有完全匹配的记录

时间:2011-06-14 07:32:31

标签: sql sql-server sql-server-2008

我有三个看起来像这样的表:

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
...

PROD RAM 之间存在由 PROD_RAM 表描述的多对多关系。

如果Ram_ID设置为(R1,R3),我想找到所有{em> ONE 或 ALL 的所有PROD给定集合的RAM

鉴于(R1,R3)应返回例如P1P4P5;我不应该返回P3,因为R1R3还有R2

获得所有PROD的{​​{1}}具有<{1>} 或 ALL Ram_ID给定RAM的最快查询是什么设置?

修改
PROD_RAM表可能包含大于1-> 3的关系,因此,对于count = 1 OR = 2的“硬编码”检查不是可行的解决方案。

3 个答案:

答案 0 :(得分:2)

你可以尝试速度的另一个解决方案就是这个

;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')
        )           

或者如果您不喜欢重复设定条件

;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        

答案 1 :(得分: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)
      )

完全不确定它是否是最快的方式。您必须尝试不同的方式来编写此查询(使用JOINNOT EXISTS)并测试速度。

答案 2 :(得分:0)

执行此操作的一种方法如下:

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