在 Postgres 中使用 NOT IN 子句时的困惑

Posted

技术标签:

【中文标题】在 Postgres 中使用 NOT IN 子句时的困惑【英文标题】:Confusion while using NOT IN clause in Postgres 【发布时间】:2016-02-16 23:17:43 【问题描述】:

我正在使用以下查询在 Amazon Redshift 上获得零结果。

查询 1:

SELECT id
FROM flx2.groups
WHERE id NOT IN (SELECT groupid FROM flx2.lmsprovidergroups)

现在,如果我将相同的查询稍微修改为:

查询 2:

SELECT id
FROM flx2.groups
WHERE id NOT IN (SELECT id
                 FROM flx2.groups
                 WHERE id IN (SELECT groupid FROM flx2.lmsprovidergroups))

我试图从lmsprovidergroups 中排除id,以从groups 中获取一个子集。为什么我必须先包含它(如查询 2 中的内部查询)然后再次排除它?

就我而言,查询 1 与查询 2 完全相同。 为什么查询 2 有效而查询 1 无效?

【问题讨论】:

使用LEFT JOIN 会更容易。而且这两个查询完全不同。 @JakubKania:您是否可以阐明这些查询有何不同?我知道我想出了它们,但我看不出它们有什么不同。我的意思是,当然,一个产生结果,另一个没有,它们必须不同。但是如何,为什么? flx2.groups.id 中有任何nulls?顺便说一句:INNOT IN 子句的子选择中的 distinct 没有用 @a_horse_with_no_name:我同意 distinct 在这种情况下没用。在flx2.groups.id 中没有nulls flx2.lmsprovidergroups.groupid 中有空值吗? 【参考方案1】:

如果NOT IN 条件的子查询至少返回一个NULL 值,则NOT IN 的计算结果为“未知”,这将导致根本没有匹配的行。

您需要从子查询中消除null 值:

SELECT id
FROM flx2.groups
WHERE id NOT IN (SELECT groupid 
                 FROM flx2.lmsprovidergroups
                 WHERE groupid is not null)

您的第二个查询基本上做同样的事情:它从子查询中消除了 null 值(假设 groups.id 不包含任何空值)

【讨论】:

【参考方案2】:

NOT IN (SELECT ...) 几乎总是一个糟糕的选择。它不仅表现出“令人惊讶”的行为,两边都有 NULL 值(如果你不熟悉逻辑),它通常也比 NOT EXISTS 的优越替代品慢:

SELECT id
FROM   flx2.groups g
WHERE  NOT EXISTS (SELECT 1 FROM flx2.lmsprovidergroups
                   WHERE  groupid = g.id);

还有其他标准技术:

Select rows which are not present in other table

【讨论】:

你让我看到了一些我不知道的事情。非常感谢。在遇到此问题之前,我几乎在编写的每个查询中都使用了NOT IN。现在我知道得更多了,谢谢你:)。

以上是关于在 Postgres 中使用 NOT IN 子句时的困惑的主要内容,如果未能解决你的问题,请参考以下文章

Postgres如何创建一个在查询中使用的函数

如何在带有 Postgres 的动态框架中使用窗口函数中的列值?

使用 liquibase 在 postgres 中删除索引的问题

如何在 Postgres/plpgsql 的视图定义中使用变量

使用 node.js 在 Postgres 中更新插入

为啥 postgres 没有在我的查询中使用索引