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