SQL 查詢條件放在LEFT OUTER JOIN 的ON語句后與放在WHERE中的區別


這兩種條件放置的位置不同很容易讓人造成混淆,以致經常查詢出莫名其妙的結果出來,特別是副本的條件與主表不匹配時,下面以A,B表為例簡單說下我的理解。

首先要明白的是:

跟在ON 后面的條件是對參與左聯接的數據進行篩選,即在左聯接之前起作用。

跟在WHERE后的條件是對左聯接得到的結果集進行篩選,即在左聯接之后起作用。

 

我直接把我的結論發出來,建議朋友們自行測試一下,下面是結論:

1) 如果條件是由主表和副表之間的字段構成,那么放在ON后與放在WHERE子條件中所得到的結果是一樣,即這種條件可以隨便放,甚至在SQL中建視圖時,會自動優化放到ON條件后。

如下:

select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND A.Name=B.UserName

select * from A LEFT OUTER JOIN B ON A.Id=B.UserId WHERE A.Name=B.UserName

上面兩個語句的結果是一樣的,如果用這條語句去建視圖,SQL管理器會自動優化成第一句的寫法,大家可以親自試驗下。

 

2)如果條件是由進行左聯接的兩個表中的一個表的字段構成,則結果會很不一樣。

1:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND B.IsDel=0 (IsDel意思為記錄是否刪除,0為否,1為是。)

2:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId WHERE B.IsDel=0

以上兩句語句使用時要非常注意,這兩種寫法得到的數據是不一樣的。

第一句的意思是:在進行左聯接前,先從表B中篩選出沒有標記為刪除的數據后得到的結果再與A表進行左聯接。

而第二句的意思是:在A,B表進行左聯接后的,再對得到的結果進行“B.IsDel=0”條件過濾。

如果A表中有2條數據,在B表中都能匹配上,那么得到的結果是一樣的,但是,假設A中只有一條記錄在B中能匹配上,那么兩條語句得到的結果就不一樣了。

因為兩表左聯接后得到的結果集中的對應B.IsDel的列(假設生命為B_IsDel)的值其實是NULL值,那么再進行“B_IsDel=0”,這條記錄就會被過濾掉了,

即最終的結果是第一條語句有兩條數據,第二條語句只有一條。

 

此外,還有下面這種更離奇的情況,假設我們的需求是對A,B兩表進行左聯接,同時希望過濾掉A表中已經被刪除了的數據和B表中已經被刪除了的數據。可能會有如下兩種寫法:

3:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND A.IsDel=0 AND B.IsDel=0 (IsDel意思為記錄是否刪除,0為否,1為是。)

4:select * from A LEFT OUTER JOIN B ON A.Id=B.UserId WHERE A.IsDel=0 AND B.IsDel=0 

 

語句4能得到想要的結果。

語句3,這種寫法很少見,執行后,大家會發現語句3的結果中包含了A表中A.IsDel=1的記錄,這是為什么呢?

原因很簡單,因為它是左聯接,下面解釋一下:

我們知道左聯接的邏輯是A表或者說主表中的數據都會出現在最終的結果集中,那么“A.IsDel=0”這個條件在語句3左聯接的過程起到了什么作用呢?

  其作用是系統在進行左聯接時,先在A表中用"A.IsDel=0"條件過濾數據(假設過濾掉了R1這條數據),用過濾后的結果再與B表進行左聯接,

  但最后整個語句返回的結果集中極會包含R1這條數據,只不過這條記錄對應的B表中的字段全部為NULL值。請大家自行測試理解。

 

此時,如果想要達到我們的目的,必需在WHERE子句中增加A.IsDel=0條件,即:

select * from A LEFT OUTER JOIN B ON A.Id=B.UserId AND A.IsDel=0 AND B.IsDel=0 WHERE A.IsDel=0

但上面這條語句比較邏輯,也完全沒必要這么寫,因此我的建議是:針對單表字段構成的篩選條件這種情況,最好的做法是直接將條件放到WHERE子句中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM