SQL 和 NOT IN 与 NULL

SQL and NOT IN with NULLs

提问人:Manngo 提问时间:3/6/2023 更新时间:3/6/2023 访问量:73

问:

我实际上正在尝试一些与子查询类似的事情,并且无法理解出了什么问题。我设法将问题简化为以下内容。

我有一个简单的表格,其中一列可能包括:NULL

DROP TABLE IF EXISTS data;
CREATE TEMP TABLE data (
    id INT PRIMARY KEY,
    number INT,
    string TEXT
);
INSERT INTO data(id,number,string)
VALUES (1,1,'Apple'),(2,1,'Accordion'),(3,2,'Banana'),(4,2,'Banjo'),(5,NULL,'Whatever');
SELECT * FROM data WHERE number IN(1,2,NULL);
SELECT * FROM data WHERE number NOT IN(1,2,NULL);

https://dbfiddle.uk/KhTzbX_E 上有一个实时版本。

当我查找与列匹配的行时:number

SELECT * FROM data WHERE number IN(1,2,NULL);

正如预期的那样,我得到了一些结果。这不包括 where is 的行,但我认为该表达式是 的缩写。numberNULLINWHERE a = b

如果我寻找不匹配项:

SELECT * FROM data WHERE number NOT IN(1,2,NULL);

我什么也没得到。

我看不出这怎么可能是正确的。表达式必须返回一个有效的列表,否则第一个列表将不起作用。IN(1,2,NULL)

这是怎么回事,有没有正确的方法可以做到这一点?

注意:我知道放入 是愚蠢的,但这个想法是该列表应该是一个可能返回 vew s 的子查询。我也知道我可以过滤掉子查询中的 s。但是,这对我来说似乎是一种解决方法。NULLNULLNULL

我已经在PostgreSQL,MariaDB和Microsoft SQL Server中尝试过。

SQL PostgreSQL null 子句内

评论


答:

0赞 dfundako 3/6/2023 #1

任何涉及 NULL 的相等性检查都将返回 null,并且 null 不等于 null。Null 需要特殊语言使用is/is not

我的建议是在你的 where 子句中添加另一部分以使其工作,并保持其可读性:

SELECT * FROM data WHERE (number NOT IN(1,2) and number is not null);
SELECT * FROM data WHERE (number IN (1,2)  or number is null);

尝试使用 null,你会看到它的行为方式:

select case when null = null then 1 else 0 end as test
0赞 Adrian Maxwell 3/6/2023 #2

IN()是一条捷径。 等同于:number IN(1,2,NULL)

(数字 = 1 或数字 = 2 或数字 = NULL)

不能对必须改用的 NULL 使用相等性,因此 IN 快捷方式将无法按预期使用 NULL 工作。IS NULL

如你所建议的,如果使用子查询,建议你去掉任何 NULL。

2赞 Erwin Brandstetter 3/6/2023 #3

基本上,如果涉及任何值,则使用非常有限。这并不是一个新见解。看:NOT INnull

nr NOT IN (1,2,NULL)

翻译为:

NOT (nr = 1 OR nr = 2 or nr = null)

nr = null总是 ,并且由于结果 ,表达式永远不会成为 。在子句中使用时,这样的过滤器永远不能返回任何行。nullfalse OR nullnulltrueWHERE

评论

0赞 jarlh 3/6/2023
我宁愿说出乎意料,而不是无用。(这完全取决于你想要什么结果。
1赞 Erwin Brandstetter 3/6/2023
@jarlh 当然,没错。我现在把“有限使用”。
2赞 Laurenz Albe 3/6/2023 #4

对于没有 NULL 经验的人来说,这是一个古老的陷阱:如果列表包含 NULL,则结果集始终为空NOT IN

为了理解原因,让我们重写

WHERE number NOT IN (1, 2, NULL)

到语义上等价的

WHERE number <> 1 AND number <> 2 AND number <> NULL

然后请注意,将始终返回 NULL。如果您将“NULL”视为“未知”,则最容易理解:当被问及未知数是否与任何给定数字不同时,答案可能是“true”或“false”,具体取决于未知数的未知值。因此,答案必须是“未知”,即值 NULL。number <> NULLboolean

现在可以是 (if is ) 或 NULL (if is NULL 或 ),但它永远不可能是 。条件仅传递条件为 的行。和 NULL 都不会通过。something AND NULLFALSEsomethingFALSEsomethingTRUETRUEWHERETRUEFALSE

评论

0赞 Manngo 3/6/2023
实际上,我对.我不知道的是表达式是如何(虚拟地)扩展的。谢谢。NULL