至少在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.code
NULL
时无效。为什么我必须专门针对NULL
本身进行测试?我会假设NULL != 4
?
答案 0 :(得分:1)
问题在于引擎是建立在三值谓词逻辑之上的。如果谓词比较两个非空值,则可以将其评估为TRUE
或FALSE
。如果其中至少有一个是NULL
,那么谓词将评估为第三个逻辑值 - UNKNOWN
。
现在WHERE
条款会发生什么?它的设计方式使它只返回谓词求值为TRUE
的行!如果谓词的计算结果为FALSE
或UNKNOWN
,则相应的行只会从结果集中过滤掉。
起初,这非常令人困惑,并导致新人进入SQL
几个典型错误的世界。他们只是认为数据可能不包含NULL
。一个典型的错误是例如:
Employyes(Name varchar, Contry varchar)
'John', 'USA'
'Peter', NULL
'Mike', 'England'
并且您希望Contry
不是USA
的所有行。你只需写下:
select * from Employees where Country <> 'USA'
并且只获得:
'Mike', 'England'
结果是。乍一看这非常令人困惑,但据您了解引擎正在进行三值逻辑,结果是合乎逻辑的。
答案 1 :(得分:0)
因为与null
进行比较,既不会产生true
也不会产生false
。它是未知。
对于我所知道的所有数据库引擎都是如此。 is
运算符会处理您已使用的null
值。
答案 2 :(得分:0)
LEFT JOIN
子句中cs.code != 4
的右侧表的WHERE
条件,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'