简体   繁体   English

MySQL LEFT JOIN和WHERE子句

[英]MySQL LEFT JOIN and WHERE clause

There is structure: 有结构:

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 http://sqlfiddle.com/#!9/028d0/5

And also there are two queries: 还有两个查询:

1 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;

2 2

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';

I'm wondering why, as a result of the second query, there is no row, in which there is NULL for content_value.value . 我想知道为什么作为第二个查询的结果,没有一行,其中content_value.valueNULL After all, the condition reads != '123' . 毕竟,条件读取为!= '123'
Who would explain this behavior to me. 谁会向我解释这种行为。

Thanks in advance. 提前致谢。

In #2, if you change where->and, it gives same results as #1. 在#2中,如果更改where-> and,则其结果与#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'

This means that the joins are getting applied after the DB engine evaluates your select .. from where .. clause. 这意味着在数据库引擎评估您的where ..子句中的select ..之后,将应用联接。

A WHERE clause further restricts the rows returned by the join query. WHERE子句进一步限制了联接查询返回的行。

More details - SQL join: where clause vs. on clause 更多详细信息-SQL连接:where子句与on子句

Use IS NOT NULL to compare NULL values because they are simply unknown. 使用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';

Working with null values 使用空值

A NULL value is never "equal to" or "not equal to" a non-NULL value. NULL值永远不会“等于”或“不等于”非NULL值。 SQL provides special "IS NULL" and "IS NOT NULL" operators for comparing to NULL values. SQL提供了特殊的“ IS NULL”和“ IS NOT NULL”运算符,用于与NULL值进行比较。

The condition in the WHERE clause of the second query negates the "outerness" of the join, by requiring content_value.value to have a non-NULL value. 通过要求content_value.value具有非NULL值,第二个查询的WHERE子句中的条件使联接的“外部性”无效。 This renders the result equivalent to an INNER JOIN. 这使结果等同于INNER JOIN。 (For the rows returned when no matching row is found, all of the columns from content_value will be NULL.) (对于找不到匹配行时返回的行, content_value所有列都将为NULL。)

It seems like you are expecting that condition to be evaluated as if it were written like this: 您似乎希望该条件的评估方式像这样编写:

  where ( content_values.value IS NULL OR content_values.value != '123' )

If portability to other DBMS isn't a concern, then we can use the MySQL specific NULL-safe comparison <=> (spaceship) operator, for example: 如果不必考虑可移植到其他DBMS的问题,那么我们可以使用MySQL特定的NULL安全比较<=> (spaceship)运算符,例如:

  where NOT ( content_values.value <=> '123' )

I'm assuming that there is a reason this condition is specified in the WHERE clause rather than the ON clause of the outer join. 我假设有一个原因在WHERE子句而不是外部联接的ON子句中指定此条件。 We can generate a different result if we move the condition from the WHERE clause to the ON clause of the outer join. 如果将条件从WHERE子句移到外部联接的ON子句,则可以生成不同的结果。

  ON content_values.content_id = contents.id
 AND content_values.field_id    = 4
 AND content_values.value      != '123'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM