2012-02-26 41 views
4

是什麼下面的SQL代碼段之間的區別:On或Where在LEFT JOIN中有什麼區別?

select count(*) 
from A 
left join B 
on a.id = b.id 
where a.status = 2 and 
b.id is NULL 

select count(*) 
from A 
left join B 
on a.id = b.id 
and a.status =2 
where b.id is NULL 

?我這樣說的:Semantic difference between join queries,但我還是不知道哪一個是更好地使用

我已經花了過去一小時附加值讀這篇文章,抓住這一切的答案,但我與「從來沒有遇到過一起理解的代碼示例這是最好的

回答

5

重寫2個查詢沒有LEFT JOIN/IS NULL所以很明顯,他們可以在某些情況下返回不同的數據集:

---Query 1 

SELECT COUNT(*) 
FROM a 
WHERE a.status = 2 
    AND NOT EXISTS 
     (SELECT * 
     FROM b 
     WHERE a.id = b.id 
    ) 

---Query 2 

SELECT COUNT(*) 
FROM a 
WHERE NOT (a.status = 2 
     AND EXISTS 
      (SELECT * 
       FROM b 
       WHERE a.id = b.id 
      ) 
     ) 

--- or: 

---Query 2 
SELECT COUNT(*) 
FROM a 
WHERE a.status <> 2 
    OR NOT EXISTS 
     (SELECT * 
     FROM b 
     WHERE a.id = b.id 
    ) 
+0

我明白了,所以查詢1更好。我正確地假設,如果它是「B.status = 2」,那麼它將在你的query2的例子1中存在()子句,所以(SELECT * from b WHERE a.id a = b.id AND b。狀態= 2)? – edelwater 2012-02-27 00:08:32

+1

查詢1和2不同,它們返回不同的結果。查詢1不是更好,但更常見。在實際情況下,我從來沒有遇到過Query2類型。 – 2012-02-27 00:10:19

+0

是的,對於第二個問題,一個'b.status = 2'條件會顯着改變事物。這是非常普遍的情況(並且讓它與左連接一起工作,您將該條件放在「ON」部分中)。 – 2012-02-27 00:12:05

10

關鍵是如何使用LEFT連接,一個會過濾結果,另一個只會失敗LEFT連接,從JOIN的左側保留數據。

(1)左加入上a.id = b.id 其中a.status = 2

忽略其它過濾器B,這表示以LEFT JOIN對錶B,因此,「嘗試使用條件a.id=b.id加入表B「。
如果不能進行匹配,請將記錄保留在左表(即A)上。繼的是,在剩餘的記錄,過濾掉(即刪除)不匹配記錄a.status=2

(2)左先連接B a.id = b.id 和a.status = 2

忽略其他過濾器,這表示在2種情況下對錶B進行左加入,因此,「試圖在條件a.id = b.id and a.status =2上加入表B」。如果在兩種條件下都沒有得到B的記錄(即使與B無關),無論如何都要保留記錄。

5

不同之處在於條件是邏輯評估的地方,反過來又會影響結果集。

在你的例子(重新格式化),您有:

實施例1

SELECT COUNT(*) 
    FROM A LEFT JOIN B ON a.id = b.id 
WHERE a.status = 2 AND b.id is NULL 

實施例2

SELECT COUNT(*) 
    FROM A LEFT JOIN B ON a.id = b.id AND a.status = 2 
WHERE b.id is NULL 

在第一種情況中,LEFT JOIN被施加並生成結果集;然後使用WHERE子句中的兩個條件對其進行過濾。

在第二種情況下,LEFT JOIN由a.status上的篩選條件構成,並且在某些情況下可能會從LEFT JOIN更改結果集。然後使用主WHERE子句過濾此結果集。

實施例2基本上等同於:

實施例2A

SELECT COUNT(*) 
    FROM (SELECT * FROM A WHERE a.status = 2) AS A 
    LEFT JOIN B ON a.id = b.id 
WHERE b.id is NULL 

對於某些查詢(但可能不是這樣的一個),差異可以無關緊要。


讓我們嘗試創建一些簡單的示例數據:

Table A    Table B 
id status   id 
4  2    1 
5  3 

實施例1將具有中間結果集:

a.id a.status b.id 
4  2   null 
5  3   null 

和WHERE子句消除的第二行。

實施例2將具有中間結果集:

a.id a.status b.id 
4  2   null 

在本例中,最終結果是一樣的,並且我還沒有能夠拿出數據不結束的相同。

如果四處移動的查詢條件位於外連接表上並且比簡單的相等性更復雜,則可以看到效果。

+1

我認爲例2只有在它是內連接時才相當。 – dotjoe 2012-02-26 23:32:17

+1

您的評論中的'that'含糊不清 - 假設您將FROM(SELECT * FROM A WHERE a.status = 2)AS A'指定爲'that'(我們稱之爲例2A),然後我挑戰你拿出一個樣本數據集,其中例2和例2A有區別。 – 2012-02-26 23:47:45

+0

@jonathan:對於您的數據集,示例2將具有包含2行的中間(和最終)結果集,而不是1.而示例2A將具有1行的結果集。 – 2012-02-26 23:58:19

1

也許這是更容易跟蹤:

SELECT id 
    FROM A 
WHERE status = 2 
EXCEPT 
SELECT id 
    FROM B; 

萬一你只是感興趣結果的基數:

SELECT COUNT(*) 
    FROM (SELECT id 
      FROM A 
      WHERE status = 2 
     EXCEPT 
     SELECT id 
      FROM B) AS DT1; 
相關問題