[英]SQL left join with filter in JOIN condition vs filter in WHERE clause
我在工作中重構了一些 sql,偶然發現了一些我不知道如何解釋的東西。 我認為有兩個查詢會導致相同的結果,但沒有,我不知道為什么。
查詢如下:
select *
from TableA as a
left join TableB b on a.id = b.id and b.status in (10, 100)
select *
from TableA as a
left join TableB b on a.id = b.id
where b.status is null or b.status in (10, 100)
這些什么時候不會返回相同的結果?
與 Where 條件b.status is null or b.status in (10, 100)
中的 b.status 的最大區別在於 b.status 是 1 以及 b.id=a.id
在第一個查詢中,您仍然會從表 A 中獲取相應 B 部分為 NULL 的行,因為 On 條件不完全滿足。 在第二個查詢中,您將獲得 a 和 b 表的 JOIN 中的行,這些行將在 where 子句中丟失。
讓我舉個例子:
SELECT * INTO #A FROM (VALUES
(1),(2),(3),(4)) T(id)
SELECT * INTO #B FROM (VALUES
(1,NULL),
(2,1),
(3,10)) T(id,status)
select *
from #A as a
left join #B b on a.id = b.id and b.status in (10, 100)
select *
from #A as a
left join #B b on a.id = b.id
where b.status is null or b.status in (10, 100)
結果
id id status
----------- ----------- -----------
1 NULL NULL
2 NULL NULL
3 3 10
4 NULL NULL
id id status
----------- ----------- -----------
1 1 NULL
3 3 10
4 NULL NULL
最終回應:
從邏輯上講,您的第二個查詢幾乎與以下內容相同:
SELECT *
FROM TableA as a
LEFT JOIN TableB b
ON a.id = b.id
WHERE b.status IN (10, 100); -- b.status is null has been removed
因此,問題歸結為ON
子句中的過濾與WHERE
子句中的過濾的標准問題。 在前一種情況下,連接左側的所有記錄都將被保留,即使ON
邏輯應該失敗。 在后一種情況下,即您的第二個查詢的情況, status
條件失敗的匹配記錄將被刪除,並且不會顯示在結果集中。
我說差不多了,因為b.status IS NULL
,你必須檢查將在事實上允許記錄生存這在連接條件沒有比賽,但碰巧有一個null
的值status
。 但是,除此之外,您的問題實際上只是ON
子句中的過濾與WHERE
子句中的過濾之一。
select * from TableA as a left join TableB b on a.id = b.id and b.status in (10, 100)
在連接發生之前評估條件語句 AND。
select * from TableA as a left join TableB b on a.id = b.id
where b.status is null or b.status in (10, 100)
過濾器在表連接后發生。
所以這就是你會得到不同輸出的原因。
由於它是LEFT JOIN
,因此不匹配的ON
條件將生成一行,其中右表中的所有列都包含NULL
。
另一方面,不匹配的WHERE
子句將完全消除該行,而不管連接類型如何。 考慮這個例子:
CREATE TABLE #TableA(id INT);
INSERT INTO #TableA VALUES
(1),
(2);
CREATE TABLE #TableB(id INT, status INT);
INSERT INTO #TableB VALUES
(1, 10),
(2, -1);
SELECT *
FROM #TableA AS A
LEFT JOIN #TableB B ON A.id = B.id AND B.status IN (10)
/*
a.id | b.id | status
1 | 1 | 10
2 | NULL | NULL
*/
SELECT *
FROM #TableA AS A
LEFT JOIN #TableB B ON A.id = B.id
-- WHERE B.status IS NULL OR B.status IN (10)
/*
a.id | b.id | status
1 | 1 | 10
2 | 2 | -1
*/
請注意,我已經注釋掉了第二個查詢中的 where 子句(結果已經不同了)。 添加后,它也會消除第二行。
在您的第一個查詢中,您將獲得左表的所有行
但
在第二個 where 當你按 where 子句過濾時,它只會給出那些完全滿足 where 條件的記錄
在正常情況下,A LEFT JOIN
或LEFT OUTER JOIN
給出左表中的所有行以及兩個表中匹配的行。 當左表中的行在右表中沒有匹配的行時,關聯的結果集行包含來自右表的所有選擇列表列的空值。
當我們添加一個帶有左外連接的 where 子句時,它的行為就像一個內連接,過濾器應用在 ON 子句之后,只顯示那些具有
B.status is null or 10 or 100
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.