【问题标题】:MySQL LEFT JOIN and WHERE clauseMySQL LEFT JOIN 和 WHERE 子句
【发布时间】:2017-04-13 19:07:02
【问题描述】:

有结构:

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

还有两个查询:

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

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'
谁会向我解释这种行为。

提前致谢。

【问题讨论】:

    标签: mysql null left-join where-clause


    【解决方案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'
    

    这意味着在数据库引擎评估您的 select .. from where .. 子句。

    WHERE 子句进一步限制连接查询返回的行。

    更多详情 - SQL join: where clause vs. on clause

    【讨论】:

      【解决方案2】:

      NULL 值永远不会“等于”或“不等于”非 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 安全比较 <=> (spaceship) 运算符,例如:

        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'
      

      【讨论】:

        【解决方案3】:

        使用 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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-09-29
          • 1970-01-01
          • 2011-07-06
          • 2021-02-15
          • 2020-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多