带有 NULL 或 IS NULL 的 IN 子句

Posted

技术标签:

【中文标题】带有 NULL 或 IS NULL 的 IN 子句【英文标题】:IN Clause with NULL or IS NULL 【发布时间】:2011-09-15 18:26:19 【问题描述】:

Postgres 是数据库

我可以对 IN 子句使用 NULL 值吗?示例:

SELECT *
FROM tbl_name
WHERE id_field IN ('value1', 'value2', 'value3', NULL)

我想限制在这四个值。

我已经尝试了上面的语句,它不起作用,它执行得很好,但没有添加带有 NULL id_fields 的记录。

我也尝试添加一个 OR 条件,但这只会让查询运行起来,而且看不到尽头。

SELECT *
FROM tbl_name
WHERE other_condition = bar
AND another_condition = foo
AND id_field IN ('value1', 'value2', 'value3')
OR id_field IS NULL

有什么建议吗?

【问题讨论】:

in 语句的解析方式与 field=val1 or field=val2 or field=val3 相同。将 null 放在那里将归结为 field=null 这将不起作用。 第二个查询应该是对的。您的where 子句中还有哪些其他内容? @Daniel A. White,更新以反映更多条件的查询 【参考方案1】:

in 语句的解析方式与 field=val1 or field=val2 or field=val3 相同。将 null 放在那里将归结为 field=null 这将不起作用。

(CommentMarc B)

我会这样做是为了清晰

SELECT *
FROM tbl_name
WHERE 
(id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL)

【讨论】:

啊,成功了,谢谢!那么包装字段会将两个条件都添加到 WHERE 子句中吗?只是为了澄清 @Phill - 这是一个操作顺序问题。【参考方案2】:

由于operator precedence,您的查询失败。 ANDOR 之前绑定! 您需要一对括号,这不是“清晰”的问题,而是纯粹的逻辑必要性

SELECT *
FROM   tbl_name
WHERE  other_condition = bar
AND    another_condition = foo
AND   (id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL);

添加的括号防止ANDOR 之前绑定。如果没有其他 WHERE 条件(没有 AND),则不需要额外的括号。接受的答案在这方面具有误导性。

【讨论】:

【参考方案3】:
SELECT *
FROM tbl_name
WHERE coalesce(id_field,'unik_null_value') 
IN ('value1', 'value2', 'value3', 'unik_null_value')

这样您就可以从检查中消除空值。给定 id_field 中的 null 值,coalesce 函数将返回 'unik_null_value' 而不是 null,并且通过将 'unik_null_value 添加到 IN 列表,查询将返回 id_field 为 value1-3 或 null 的帖子。

【讨论】:

稍微解释一下会对以后的读者有所帮助。您的代码如何帮助解决问题? 来自文档:COALESCE() 函数返回列表中的第一个非空值。因此,当 id_field 为 null 时,将返回 'unik_null_value' 并查询返回正确的记录。【参考方案4】:

丹尼尔回答的问题非常好。我想留下关于 NULLS 的说明。当列包含 NULL 值时,我们应该小心使用 NOT IN 运算符。如果您的列包含 NULL 值并且您使用的是 NOT IN 运算符,您将不会得到任何输出。这就是在这里http://www.oraclebin.com/2013/01/beware-of-nulls.html 的解释方式,这是一篇非常好的文章,我偶然发现并想分享它。

【讨论】:

不确定有多少用户遇到过这个问题,但我遇到了混合空值和 NOT IN 运算符的确切问题,并且在过去两个小时内一直在胡乱讨论。这是perp ... 链接已失效。 现在还活着。【参考方案5】:

注意:由于有人声称 Sushant Butta 的回答中的外部链接已失效,因此我已将内容作为单独的回答发布在这里。

当心NULLS

今天我在使用 IN 和 NOT IN 运算符时遇到了一个非常奇怪的查询行为。实际上,我想比较两个表并找出table b 中的值是否存在于table a 中,并找出列是否包含null 值的行为。所以我只是创建了一个环境来测试这种行为。

我们将创建表table_a

SQL> create table table_a ( a number);
Table created.

我们将创建表table_b

SQL> create table table_b ( b number);
Table created.

table_a 中插入一些值。

SQL> insert into table_a values (1);
1 row created.

SQL> insert into table_a values (2);
1 row created.

SQL> insert into table_a values (3);
1 row created.

table_b 中插入一些值。

SQL> insert into table_b values(4);
1 row created.

SQL> insert into table_b values(3);
1 row created.

现在我们将执行一个查询来检查 table_a 中的值是否存在,方法是使用 IN 运算符检查来自 table_b 的值。

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

执行以下查询以检查不存在。

SQL> select * from table_a where a not in (select * from table_b);
         A
----------
         1
         2

输出符合预期。现在我们将在表table_b 中插入一个null 值,并查看上述两个查询的行为。

SQL> insert into table_b values(null);
1 row created.

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

SQL> select * from table_a where a not in (select * from table_b);

no rows selected

第一个查询的行为符合预期,但第二个查询发生了什么?为什么我们没有得到任何输出,应该发生什么?查询有什么不同吗?

更改在表table_b 的数据中。我们在表中引入了null 值。但它怎么会这样呢?让我们将这两个查询拆分为"AND""OR" 运算符。

第一个查询:

第一个查询将像这样在内部处理。所以null 不会在这里产生问题,因为我的前两个操作数将评估为truefalse。但是我的第三个操作数a = null 既不会计算为true 也不会计算为false。它将仅评估为 null

select * from table_a whara a = 3 or a = 4 or a = null;

a = 3  is either true or false
a = 4  is either true or false
a = null is null

第二次查询:

第二个查询将按如下方式处理。由于我们在任何操作数中使用"AND" 运算符和true 以外的任何操作数都不会给我任何输出。

select * from table_a whara a <> 3 and a <> 4 and a <> null;

a <> 3 is either true or false
a <> 4 is either true or false
a <> null is null

那么我们该如何处理呢?我们将在使用NOT IN 运算符时从表table_b 中选择所有not null 值。

SQL> select * from table_a where a not in (select * from table_b where b is not null);

         A
----------
         1
         2

因此,在使用 NOT IN 运算符时,请务必注意列中的 NULL 值。

小心 NULL!!

【讨论】:

优秀的答案。我刚刚在工作中发现了这个问题。 Oracle 非常非常奇怪的行为。【参考方案6】:

我知道回答晚了,但可能对其他人有用 您可以使用子查询并将 null 转换为 0

SELECT *
FROM (SELECT CASE WHEN id_field IS NULL 
                THEN 0 
                ELSE id_field 
            END AS id_field
      FROM tbl_name) AS tbl
WHERE tbl.id_field IN ('value1', 'value2', 'value3', 0)

【讨论】:

这类似于 Ove Halseth 使用合并的答案。【参考方案7】:

Null 表示缺少数据。 Null 正式定义为不可用、未分配、未知或不适用的值(OCA Oracle Database 12c,SQL Fundamentals I Exam Guide,p87)。 因此,当使用“in”或“not in”子句限制所述列时,您可能看不到列包含空值的记录。

【讨论】:

以上是关于带有 NULL 或 IS NULL 的 IN 子句的主要内容,如果未能解决你的问题,请参考以下文章

WHERE IS NULL、IS NOT NULL 或 NO WHERE 子句取决于 SQL Server 参数值

EF4 将 is null 子句添加到 where 子句

MySQL使用select in or子句的结果[重复]

NOT IN 子句中的 NULL 值

SQL Server:查询应用在 where 子句中,包含 Json 对象的列上的 IS NOT Null 需要更多时间

SQL语句中 NOT IN 子句的“正确打开方式”