SQL外部查詢NOT IN內部查詢引用外部查詢

[英]SQL Outer Query NOT IN Inner Query referencing Outer Query


I have a bit of a T-SQL conundrum that appears to be working but I was wondering if someone could attempt to give me a breakdown as to what is happening here.Consider the following script:

我有一點似乎有效的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())

I'm rather stumped as to how the compiler is not imploding on this script. How can it select where NOT IN on a subquery referencing the outer query? Get contents of TableA where CustomerID NOT IN CustomerID's from TableB etc... But when it finds a matching CustomerID in the subquery, the NOT IN kicks in and prevents the record from showing in the outer query select. I'm guessing this is where the compiler stops. But then because that specific CustomerID is not selected, it cannot join in the inner query, thus inner query does not select that CustomerID, then allowing the outer query to select that record? Yes? No? Falling down the rabbit hole? Is there a better way to write this?

關於編譯器如何不對這個腳本進行內爆,我感到非常難過。如何在引用外部查詢的子查詢中選擇NOT IN的位置?獲取TableA的內容,其中CustomerID不是來自TableB等的CustomerID ...但是當它在子查詢中找到匹配的CustomerID時,NOT IN會啟動並阻止記錄顯示在外部查詢選擇中。我猜這是編譯器停止的地方。但是因為沒有選擇特定的CustomerID,它不能加入內部查詢,因此內部查詢不選擇那個CustomerID,然后允許外部查詢選擇該記錄?是?沒有?掉下兔子洞?有沒有更好的方法來寫這個?

Would appreciate if someone could elaborate on what happening here, or reference something that could explain. I could't really find anyone explaining this process, maybe not using the right search terms.

如果有人可以詳細說明這里發生的事情,或者參考可以解釋的事情,我將不勝感激。我真的找不到任何人解釋這個過程,也許沒有使用正確的搜索詞。

Thank you!

謝謝!

1 个解决方案

#1


3  

It is called a "Correlated subquery" and "the subquery may be evaluated once for each row processed by the outer query".

它被稱為“相關子查詢”和“子查詢可以為外部查詢處理的每一行評估一次”。

So here, for each row of TableA, the subquery seeks the matching data from TableB and determines if the NOT IN condition is met. Then on to the next row in TableA to repeat that cycle until all relevant rows of TableA have been evaluated.

所以在這里,對於TableA的每一行,子查詢從TableB中尋找匹配數據並確定是否滿足NOT IN條件。然后轉到TableA中的下一行重復該循環,直到評估了TableA的所有相關行。

An alternative approach could be a "left excluding join" when you join the 2 tables but then ignore rows where a join exists.

當您加入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())
;

or another "semi-join" alternative by using NOT EXISTS:

或使用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())
;

Note that the subquery used for |NOT| EXISTS doesn't have to return any values through the select clause. Some prefer to use "select 1" or "select *" when using EXISTS but in truth it really doesn't matter which is used. Using "select NULL" is my preference.

請注意,子查詢用於| NOT | EXISTS不必通過select子句返回任何值。有些人喜歡在使用EXISTS時使用“select 1”或“select *”,但實際上使用哪個並不重要。使用“select NULL”是我的偏好。

You can learn more about these alternatives by inspecting execution plans, see http://sqlfiddle.com/#!6/04064/2 for example.

您可以通過檢查執行計划來了解有關這些替代方案的更多信息,例如參見http://sqlfiddle.com/#!6/04064/2。

Original query:enter image description here "Left excluding join" alternative:enter image description here "Not Exists" alternative:enter image description here

原始查詢:“左排除加入”替代:“不存在”替代方案:


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2017/08/10/720517df41f564b2952d39555e073033.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com