寻找NOT IN时PostgreSQL Null中断列表

Cal*_*YSR 1 postgresql

我认为这可能是PostgreSQL的错误,但是我在这里发布了它,以防万一我丢失了一些东西。当我的WHERE子句有一个NOT IN ()子句时,null在列表中包含该子句将不再是真实的。下面是我的问题的一个愚蠢的例子。

=# select 1 where 1 not in (1);
 ?column? 
----------
(0 rows)

=# select 1 where 1 not in (2);
 ?column? 
----------
        1
(1 row)

=# select 1 where 1 not in (null);
 ?column? 
----------
(0 rows)

=# select 1 where 1 not in (null, 2);
 ?column? 
----------
(0 rows)

=# select 1 where 1 not in (2, null);
 ?column? 
----------
(0 rows)

=# select 1 where 1 not in (2, 3);
 ?column? 
----------
        1
(1 row)

Run Code Online (Sandbox Code Playgroud)

因此where 1 not in (1),由于1在列表中,所以按预期返回0行,由于不在列表中,所以按预期where 1 not in (2)返回1行,即使不在1列表中,也where 1 not in (null)返回0行1

Bru*_*uno 5

这不是PostgreSQL错误。

问题在于,这NOT IN只是一个用于测试所有不平等现象的简短版本。

1 NOT IN (null, 2) 等效于:

1 <> null
AND
1 <> 2
Run Code Online (Sandbox Code Playgroud)

但是,NULL是一个特殊值,1 <> null本身NULL(不是TRUE)也是如此。请参阅文档

不要写expression = NULL,因为NULL不等于NULL。(空值表示一个未知值,并且未知两个未知值是否相等。)

据我所知,这是标准的SQL行为。

PostgreSQL还有一个额外的关键字来检查值是否不同于null:

1 IS DISTINCT FROM NULL会是TRUE

  • *“据我所知,这是标准的SQL行为。” *实际上SQL 2003定义了*“ 4.6.1布尔值的比较和赋值所有布尔值数据类型值和SQL真值都可以相互比较和分配。值true大于值false和**涉及空值或未知真值的任何比较将返回未知结果**“ **这也意味着优化器可以直接用`null`预处理'1 &lt;&gt; null`并替换`null AND 1 &lt;&gt; 2`也带有`null`。。不确定PostgreSQL optimizier是否进行这种预处理。 (2认同)
  • @RaymondNijland:是的,优化器将“ 1 &lt;&gt; null”(或“列&lt;&gt; null”)替换为“ false”(在执行计划中,您将看到一行带有“一次性过滤器:false”的行) (2认同)