SQL 外部查询不在引用外部查询的内部查询中

SQL Outer Query NOT IN Inner Query referencing Outer Query

我有一些 T-SQL 难题似乎有效,但我想知道是否有人可以尝试向我详细说明正在发生的事情 here.Consider 以下脚本:

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())

我很困惑编译器如何没有在这个脚本上崩溃。它如何 select 在引用外部查询的子查询中的 NOT IN 位置?从 TableB 等中获取 TableA 的内容,其中 CustomerID NOT IN CustomerID 等...但是当它在子查询中找到匹配的 CustomerID 时,NOT IN 开始并阻止记录显示在外部查询中 select。我猜这是编译器停止的地方。但是因为那个特定的CustomerID没有selected,它不能加入内部查询,因此内部查询没有select那个CustomerID,那么允许外部查询select那个记录?是的?不?掉进兔子洞?有没有更好的写法?

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

谢谢!

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

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

另一种方法可能是 "left excluding join" 当您连接 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())
;

或另一个 "semi-join" 替代方案,使用 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 子句 return 任何值。有些人喜欢在使用 EXISTS 时使用 "select 1" 或 "select *",但实际上使用哪个并不重要。使用 "select NULL" 是我的偏好。

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

原查询: "Left excluding join"备选方案: "Not Exists"备选方案: