2015-11-18 97 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'