簡體   English   中英

SQL 左連接與 JOIN 條件中的過濾器與 WHERE 子句中的過濾器

[英]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

最終回應:

  1. 如果狀態不在 (10,100) 中,則 LEFT JOIN 應用 NULL
  2. 如果狀態為 NULL,LEFT JOIN 也適用 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 JOINLEFT OUTER JOIN給出左表中的所有行以及兩個表中匹配的行。 當左表中的行在右表中沒有匹配的行時,關聯的結果集行包含來自右表的所有選擇列表列的空值。

當我們添加一個帶有左外連接的 where 子句時,它的行為就像一個內連接,過濾器應用在 ON 子句之后,只顯示那些具有

B.status is null or 10 or 100

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM