的MySQL LEFT JOIN和WHERE子句
问题描述:
CREATE TABLE `contents` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
CREATE TABLE `content_values` (
`content_id` INT UNSIGNED NOT NULL,
`field_id` INT UNSIGNED NOT NULL,
`value` VARCHAR(45) NULL,
PRIMARY KEY (`content_id`, `field_id`));
INSERT INTO `contents` VALUES (1,'test-title-1'),(2,'test-title-2');
INSERT INTO `content_values` VALUES (1,4,'test-value');
http://sqlfiddle.com/#!9/028d0/5
而且也有两个疑问:
select contents.*, content_values.value
from contents
left join content_values on content_values.content_id=contents.id and
content_values.field_id = 4;
select contents.*, content_values.value
from contents
left join content_values on content_values.content_id=contents.id and
content_values.field_id = 4
where content_values.value != '123';
我想知道为什么,作为第二个查询的结果,没有行,其中有NULL
为content_value.value
。毕竟,条件为!= '123'
。
谁会向我解释这种行为。
在此先感谢。
答
使用IS NOT NULL来比较NULL值,因为它们只是未知的。
select contents.*, content_values.value
from contents
LEFT join content_values
on content_values.content_id=contents.id and content_values.field_id=4
where content_values.value IS NULL OR content_values.value != '123';
答
在#2,如果你改变,而─>和,它提供了相同的结果,#1。
select contents.*, content_values.value
from contents
left join content_values on content_values.content_id=contents.id and content_values.field_id=4
**and** content_values.value != '123'
这意味着加入越来越应用于数据库引擎评估你的 选择..从那里..子句之后。
WHERE子句进一步限制连接查询返回的行。
答
甲NULL
值从不“等于”或“不等于”非空值。 SQL提供了特殊的“IS NULL”和“IS NOT NULL”运算符来与NULL值进行比较。
第二个查询的WHERE子句中的条件通过要求content_value.value具有非NULL值来抵消连接的“外部”。这使得结果等同于INNER JOIN。 (对于行返回时,没有找到匹配的行,所有列从content_value
将是NULL。)
好像你正期待就好像它是这样写的,以评估该条件:
where (content_values.value IS NULL OR content_values.value != '123')
如果移植到其他DBMS不是问题,那么我们就可以使用MySQL的具体NULL安全比较<=>
(飞船)运算符,例如:
where NOT (content_values.value <=> '123')
我假设在WHERE子句中指定了这个条件,而不是外连接的ON子句。如果将条件从WHERE子句移动到外部联接的ON子句,我们可以生成不同的结果。
ON content_values.content_id = contents.id
AND content_values.field_id = 4
AND content_values.value != '123'