2015-11-18 128 views
0

至少在MariaDB v10.x中,爲什麼具有左連接的真子句不起作用,因爲我期望有NULL的返回值?左連接奇怪

以下工作:

SELECT 
    u.id 
FROM 
    user u 

    INNER JOIN role r on r.user = u.id 
    INNER JOIN customer c ON c.id = r.customer 
    LEFT JOIN customer_subclass cs ON cs.customer = c.id 

WHERE 
    u.status = 'NEW' AND (cs.code != 4 OR cs.code IS NULL) 

,但是當我第一次嘗試

WHERE 
    u.status = 'NEW' AND cs.code != 4 

cs.codeNULL沒有奏效。爲什麼我必須專門針對NULL本身進行測試?我會假設NULL != 4

+1

將cs.code!= 4移動到ON子句以獲得真正的LEFT JOIN行爲。 – jarlh

回答

1

事情是引擎是基於三值謂詞邏輯構建的。如果謂詞比較兩個非空值,則可以將其評估爲TRUEFALSE。如果至少有一個是NULL,則謂詞評估爲第三邏輯值 - UNKNOWN

現在在WHERE子句中會發生什麼?它的設計方式使得它僅返回謂詞僅僅計算爲TRUE的行!如果謂詞計算結果爲FALSEUNKNOWN,則相應的行僅從結果集中過濾出來。

起初這是非常混亂,並導致新來到SQL的世界幾個典型的錯誤。他們只是不認爲該數據可能包含NULL s。一個典型的錯誤是例如:

Employyes(Name varchar, Contry varchar) 
'John', 'USA' 
'Peter', NULL 
'Mike', 'England' 

你想要的所有行ContryUSA。而你只寫:

select * from Employees where Country <> 'USA' 

,只得到:

'Mike', 'England' 

結果。乍看起來這很混亂,但據你所知,引擎正在做三值邏輯,結果是合乎邏輯的。

0

因爲與null比較的結果都不是true也不是false。這是未知

這對我所知道的所有數據庫引擎都是如此。 is運算符特別處理您已經使用的值,其值爲null

0

隨着LEFT JOINWHERE子句中cs.code != 4條件的右側表條件,LEFT JOIN作爲常規INNER JOIN執行。

解決方法是將該條件移至ON子句,以獲得真實的LEFT JOIN行爲。

SELECT 
    u.id 
FROM 
    user u 

    INNER JOIN role r on r.user = u.id 
    INNER JOIN customer c ON c.id = r.customer 
    LEFT JOIN customer_subclass cs ON cs.customer = c.id AND cs.code != 4 

WHERE 
    u.status = 'NEW'