【问题标题】:Why isn't 'WHERE NOT' with NULL-rows working?为什么 NULL 行的“WHERE NOT”不起作用?
【发布时间】:2022-01-06 01:28:34
【问题描述】:

也许我只是错过了一些东西。由于问题太不具体,无法通过谷歌搜索/搜索,我现在在这里寻求帮助。在 MySQL

中测试

我的问题:为什么这个 SELECT 不输出 [id=2]?

SELECT `id` FROM `testtable1` WHERE NOT (`key_boolean` = 1);

表定义和测试数据:

CREATE TABLE IF NOT EXISTS `testtable1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key_boolean` tinyint NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;

INSERT INTO `testtable1` (`key_boolean`) VALUES (1);
INSERT INTO `testtable1` () VALUES ();

现在存储在表中:

id key_boolean
1 1
2 NULL

编辑: 根据答案,我实际上在 StackOverflow 上发现了一些更类似的问题。这篇文章非常适合 MySQL:MYSQL syntax not evaluating not equal to in presence of NULL

【问题讨论】:

    标签: mysql sql where-clause


    【解决方案1】:

    key_booleanNULL 时,表达式key_boolean = 1 的计算结果为NULL。所以你中间有NOT NULLNOT (key_boolean = 1)NOT NULL 反过来也计算为 NULL。由于NULL 不是真的(但也不是假的——在SQL 中ternary logic 适用),所以不会选择该行。

    除了少数之外,所有比较操作(如=)的计算结果为NULL,如果它们的操作数之一是NULL。在这种情况下,MySQL 中一个值得注意的例外是 NULL-safe equal <=>,它的行为就像您可能想要的那样。

    您可以从测试表中选择(子)表达式并亲自查看它们的结果。

    SELECT *,
           key_boolean = 1,
           NOT (key_boolean = 1),
           key_boolean <=> 1,
           NOT (key_boolean <=> 1)
           FROM testtable1;
    

    db<>fiddle

    【讨论】:

      【解决方案2】:

      就个人而言,我发现@sticky-bit 和@ysth 的答案非常有帮助,但我想分享一些关于我的研究的更多信息:

      结论: SQL 遵循三值逻辑 (3VL)。这意味着除了 TRUE(1) 和 FALSE(0) 之外,还有 NULL。这意味着如果比较中的操作数之一为 NULL,则结果也为 NULL。另见维基百科上的真值表:https://en.wikipedia.org/wiki/Null_(SQL)#Comparisons_with_NULL_and_the_three-valued_logic_(3VL)


      没有 NOT 的示例 1:

      SELECT id FROM testtable1 WHERE (key_boolean = 1);,所以:

      • [第 1 行]key_boolean = 1 --> 1 = 1 --> 正确
      • [第 2 行]key_boolean = 1 --> NULL = 1 --> NULL

      -> 所以,第 1 行被选中。

      例2,和例1一样,只是取反,所以用NOT

      SELECT id FROM testtable1 WHERE NOT (key_boolean = 1);,所以

      • [第 1 行] 非 (key_boolean) = 1 --> 1 = 1 --> 真
      • [第 2 行] NOT (key_boolean) = 1 --> NULL = 1 --> NULL

      -> 空结果。


      问题的解决方案:

      正如@sticky-bit 已经写的那样,MySQL 中有 NULL-safe equal,在这个例子中也达到了预期的结果。 不幸的是,它只适用于 MySQL(然后也适用于 MariaDB)。我在https://modern-sql.com/feature/is-distinct-from 找到了不同方言的比较。 @ysth 的“CASE WHEN”建议可能适用于所有方言,但会破坏选择术语。

      在我的特定情况下(不再是实际问题的一部分)我现在已经用COALESCE() 解决了它 - 确定了 NULL 值的默认值,因为在我的情况下,我不仅要支持 mysql,请参阅:

      SELECT `id` FROM `testtable1` WHERE NOT (COALESCE(`key_boolean`, 0) = 1);
      

      进一步阅读: 如果像我一样,从未听说过 NULL 安全的相等运算符 ,请参阅:What is this operator <=> in MySQL?

      现在我绝不是数据库技术人员,但知道 NULL 是未定义的(来自其他编程语言)。对我来说显而易见的问题是为什么至少 SQL 不会每次都使用 NULL 安全的 equal。请参阅:Is there a reason not to use <=> (null safe equals operator) in mysql instead of =?Is there a reason not to use <=> (null safe equals operator) in mysql instead of =? [每个都有标记的帖子]。

      【讨论】:

        【解决方案3】:

        NULL 在概念上意味着不确定。所以 NOT NULL 也是 NULL,而且是假的。如果要包含 NULL,可以测试 CASE WHEN key_boolean=1 THEN 0 ELSE 1 END

        【讨论】:

        • 我明白了。但是为什么这(NULL = 不确定)在我的特定 WHERE 中很重要?在这种情况下,我首先查找key_boolean=1,然后否定结果。基本上是 WHERE IN WHERE:“SELECT id FROM testtable1 WHERE id NOT IN (SELECT id FROM testtable1 WHERE key_boolean = 1);”
        • 如果不确定,则不明确=1,但也不明确!=1。
        • 好吧,引用“如果不确定,则不清楚 =1”一开始是件好事。术语“SELECT id FROM testtable1 WHERE key_boolean = 1;”也只输出 [id = 1]。那么,为什么 mysql 不首先评估内部术语“key_boolean = 1”(输出 [id = 1])然后否定内部术语的结果? “也不清楚!= 1”应该是无关紧要的,不是吗?我错过了什么?
        • 我不确定您缺少什么。如果= 的任一操作数为NULL,则结果为NULL。所以如果key_boolean 为NULL,key_boolean = 1 为NULL。和NOT( key_boolean = 1 )NOT NULL 仍然是NULL。
        • 非常感谢您的回复。是的,现在这对我来说很有意义。
        猜你喜欢
        • 2014-01-10
        • 1970-01-01
        • 2013-02-17
        • 2016-05-19
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多