为什么 NULL 行的'WHERE NOT'不起作用?



也许我只是错过了什么。由于这个问题太不具体,无法在谷歌上搜索,我现在正在这里寻求帮助。在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 ();

表中现在存储:

idkey_boolean
11
2NULL

key_booleanNULL时,表达式key_boolean = 1的计算结果为NULL。所以你中间有NOT NULL代替NOT (key_boolean = 1)NOT NULL反过来也计算为NULL。由于NULL不是true(但也不是false——在SQL中应用三元逻辑(,因此不会选择该行。

除了少数操作数外,所有的比较操作,如=,如果它们的操作数之一是NULL,则求值为NULL。MySQL中的一个值得注意的例外,在这种情况下,是NULL-安全等价的<=>,它的行为就像您可能想要的那样

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

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

db<gt;小提琴

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

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


没有NOT的示例1:

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

  • [行1]key_boolean=1->1=1->真的
  • [行2]CCD_ 17=1->NULL=1->NULL

->因此,行1被选择

示例2和示例1一样,只是取反,因此​带有NOT

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

  • [行1]NOT(key_boolean(=1->1=1->真的
  • [行2]NOT(key_boolean(=1->NULL=1->NULL

->空结果


问题解决方案:

正如@stickbit已经写过的,MySQL中有NULL安全的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安全相等运算符<>,请参阅:这个运算符是什么<>在MySQL中?

现在我绝不是一个数据库技术人员,但我知道NULL是未定义的(来自其他编程语言(。对我来说,一个显而易见的问题是,为什么至少SQL每次都不使用NULL安全当量。请参阅:是否有理由不使用<>(null safe equals运算符(而不是=?以及是否有理由不使用<>(null safe equals运算符(而不是=?[每个都有一个标记的帖子]。

NULL在概念上表示不确定。所以NOT NULL也是NULL,也是false。如果要包含NULL,可以测试CASE WHEN key_boolean=1 THEN 0 ELSE 1 END

最新更新