2017-08-10 85 views
1

我有一點似乎正在工作的T-SQL難題,但我想知道是否有人可以嘗試給我一個故障,以瞭解這裏發生的事情。考慮以下腳本: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?從TableB等獲取TableA的CustomerID不在CustomerID中的內容...但是,如果在子查詢中找到匹配的CustomerID,則NOT IN會啓動並阻止記錄顯示在外部查詢選擇中。我猜這是編譯器停止的地方。但是由於沒有選擇特定的CustomerID,它不能加入內部查詢,因此內部查詢不會選擇該CustomerID,然後允許外部查詢選擇該記錄?是?沒有?落下兔子洞?有沒有更好的方式來寫這個?

希望有人能詳細說明這裏發生的事情,或引用可以解釋的事情。我無法找到任何人解釋這個過程,也許沒有使用正確的搜索條件。

謝謝!

回答

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 *」,但事實上,使用哪一個並不重要。使用「選擇NULL」是我的首選。

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

原始查詢:enter image description here 「左排除加入」另類:enter image description here 「不存在」的選擇:enter image description here

+0

謝謝這有助於澄清,我不知道有它的名稱!你能解釋一些關於WHERE NOT EXISTS(SELECT NULL)嗎?如果子查詢返回一個NULL,那麼會被認爲是「EXISTING」呢?我喜歡這種方法,因爲我的TableA select絕對不能因爲連接問題返回任何dups ,TableA和TableB實際上有大約300列,並且是直接連接在一起時經常不可信的客戶數據。 – Xenophage

+1

我已經添加了一個關於「select NULL」的註釋,我可以說沒關係,重點是它是視爲*「幾乎是一個連接」*(事實上是「左反半連接」),因此子查詢的select子句並未真正考慮,只是where子句足以確定匹配是否存在。 :請注意,「left excluded join」不會乘以結果的行,因爲只返回UNMATCHED行。 –