加入"存在"子查询

时间:2017-01-04 19:45:51

标签: sql sql-server tsql join

我想知道为什么当你在exists子查询中的一个键上连接两个表时,连接必须在WHERE子句而不是FROM子句中发生。

这是我的例子:

加入FROM子句:

SELECT payer_id
  FROM Population1
 WHERE NOT EXISTS
       (Select *
          From Population2 join Population1 
            On Population2.payer_id = Population1.payer_id)

加入WHERE子句:

SELECT payer_id
  FROM Population1
  WHERE NOT EXISTS
        (Select *
           From Population2
          WHERE Population2.payer_id = Population1.payer_id)

第一个查询给出了0结果,我知道这是不正确的,而第二个查询给出了我期望看到的数千个结果。

有人可以向我解释为什么在EXISTS子查询中发生连接的重要性?如果你在没有父查询的情况下获取子查询并运行它们,它们会给你相同的结果。

在使用存在时,记住不要继续犯这个错误会对我有所帮助。

提前致谢。

3 个答案:

答案 0 :(得分:6)

您需要了解常规子查询与相关子查询之间的区别。

使用您的示例,这应该很容易。第一个where子句是:

where not exists (Select 1
                  from Population2 join
                       Population1
                       on Population2.payer_id = Population1.payer_id
                 )

这种情况完全它所说的正在做什么。子查询与外部查询没有任何关联。因此,not exists将过滤掉所有行或保留所有行。

在这种情况下,引擎运行子查询并确定至少返回一行。因此,not exists在所有情况下都返回false,并且不返回任何内容。

在第二种情况下,子查询是相关子查询。因此,对于population1中的每一行,子查询都使用Population1.payer_id的值运行。在某些情况下,Population2中存在匹配的行;这些被过滤掉了。在其他情况下,匹配的行不存在;这些都在结果集中。

答案 1 :(得分:0)

第一个例子实际上并不是在创建一个不可预测的逻辑的基表上。

执行相同逻辑的另一种方法是:

SELECT payer_id
FROM Population1 P1
LEFT JOIN Population2 P2 ON
    P2.Payer_Id = P1.Payer_Id
WHERE
    P2.Payer_Id IS NULL

答案 2 :(得分:0)

即使存在一个结果行,您也总是存在返回ROW EXISTS

Select *
from Population2 
join Population1 on Population2.payer_id = Population1.payer_id

如果此联接中至少存在一行(并且肯定存在),您可以想象您的子目标如下:

select 'ROW EXISTS'

结果:

select * 
from Population1
where not exists (select 'ROW EXISTS')

所以你的反半连接回归:

payer_id 1 - >一些ROW EXISTS - >不要返回这一行

payer_id 2 - >一些ROW EXISTS - >不要返回这一行