SQL外部查询NOT IN内部查询引用外部查询

时间:2017-08-10 23:29:15

标签: sql sql-server-2008-r2 inner-query

我有一些似乎有效的T-SQL难题,但我想知道是否有人可以试图告诉我这里发生的事情。请考虑以下脚本:

SELECT *
FROM TableA a
WHERE a.CustomerID NOT IN (SELECT b.CustomerID FROM TableB b WHERE a.CustomerID = b.CustomerID AND a.WorkOrder = b.WorkOrder)
AND a.[Date] > DATEADD(DD,-3,GETDATE())

对于编译器如何不对此脚本进行内爆,我感到非常难过。如何在引用外部查询的子查询中选择NOT IN的位置?获取TableA的内容,其中CustomerID不是来自TableB等的CustomerID ...但是当它在子查询中找到匹配的CustomerID时,NOT IN启动并阻止记录显示在外部查询选择中。我猜这是编译器停止的地方。但是因为没有选择特定的CustomerID,它无法加入内部查询,因此内部查询不会选择该CustomerID,然后允许外部查询选择该记录?是?没有?掉下兔子洞?有没有更好的方法来写这个?

如果有人可以详细说明这里发生的事情,或者引用可以解释的内容,我们将不胜感激。我真的找不到任何人解释这个过程,也许没有使用正确的搜索词。

谢谢!

1 个答案:

答案 0 :(得分:3)

它被称为“Correlated subquery”和“子查询可以为外部查询处理的每一行评估一次”。

所以在这里,对于TableA的每一行,子查询从TableB中寻找匹配数据并确定是否满足NOT IN条件。然后转到TableA中的下一行重复该循环,直到评估了TableA的所有相关行。

当您加入2个表时,另一种方法可能是“左排除连接”,但忽略存在连接的行。

SELECT
      *
FROM TableA a
LEFT JOIN TableB b ON a.CustomerID = b.CustomerID
                  AND a.WorkOrder = b.WorkOrder
WHERE b.CustomerID IS NULL
AND a.[Date] > DATEADD(DD, -3, GETDATE())
;

或使用NOT EXISTS的其他“半连接”替代方案:

SELECT
      *
FROM TableA a
WHERE NOT EXISTS (
      SELECT NULL
      FROM TableB b
      WHERE a.CustomerID = b.CustomerID
      AND a.WorkOrder = b.WorkOrder
      )
AND a.[Date] > DATEADD(DD, -3, GETDATE())
;

请注意,子查询用于| NOT | EXISTS不必通过select子句返回任何值。有些人喜欢在使用EXISTS时使用“select 1”或“select *”,但实际上使用哪个并不重要。使用“select NULL”是我的首选。

您可以通过检查执行计划了解有关这些替代方案的更多信息,例如,请参阅http://sqlfiddle.com/#!6/04064/2

原始查询:enter image description here “左排除加入”替代方案:enter image description here “不存在”替代方案:enter image description here