如何在没有多个EXISTS子句的情况下返回表中匹配的行?

时间:2012-06-05 16:21:34

标签: sql sql-server tsql

我想从一个匹配 ALL 指定值的表中提取结果,其中指定的值在另一个表中。我可以这样做:

SELECT * FROM Contacts 
WHERE 
EXISTS (SELECT 1 FROM dbo.ContactClassifications WHERE ContactID = Contacts.ID AND ClassificationID =  '8C62E5DE-00FC-4994-8127-000B02E10DA5')
AND EXISTS (SELECT 1 FROM dbo.ContactClassifications WHERE ContactID = Contacts.ID AND ClassificationID =  'D2E90AA0-AC93-4406-AF93-0020009A34BA')
AND EXISTS etc...

然而,当我达到约40项EXISTS条款时,这种情况就会失败。错误消息是“查询处理器耗尽了内部资源,无法生成查询计划。这是一种罕见的事件,仅适用于引用大量表或分区的极其复杂的查询或查询。请简化查询。“

3 个答案:

答案 0 :(得分:6)

这要点是

  • IN声明
  • 中选择包含任何GUID的所有联系人
  • 使用DISTINCT COUNT获取与GUID匹配的每个联系人的计数
  • 使用HAVING仅保留那些与您在IN语句中放入的匹配GUID数量相等的联系人

SQL声明

SELECT *
FROM   dbo.Contacts c
       INNER JOIN (
          SELECT c.ID
          FROM   dbo.Contacts c
                 INNER JOIN dbo.ContactClassifications cc ON c.ID = cc.ContactID
          WHERE  cc.ClassificationID IN ('..', '..', 38 other GUIDS)
          GROUP BY
                 c.ID
          HAVING COUNT(DISTINCT cc.ClassificationID) = 40
       ) cc ON cc.ID = c.ID

data.stackexchange

的测试脚本

答案 1 :(得分:3)

一种解决方案是要求在没有匹配联系人的情况下不存在分类。这是一个双重否定:

select  *
from    contacts c
where   not exists
        (
        select  *
        from    ContactClassifications cc
        where   not exists
                (
                select  *
                from    ContactClassifications cc2
                where   cc2.ContactID = c.ID
                        and cc2.ClassificationID = cc.ClassificationID
                )
        )

此类问题称为relational division

答案 2 :(得分:0)

SELECT c.* 
FROM Contacts c
INNER JOIN 
 (cc.ContactID, COUNT(DISTINCT cc.ClassificationID) as num_class
  FROM ContactClassifications 
  WHERE  ClassificationID IN (....)
  GROUP BY cc.ContactID 
 ) b ON c.ID = b.ContactID
WHERE b.num_class = [number of distinct values - how many different values you put in "IN"]

如果您运行SQLServer 2005及更高版本,您可以使用CROSS APPLY执行相同的操作,假设效率更高