【问题标题】:NOT EXISTS clause in PostgresqlPostgresql 中的 NOT EXISTS 子句
【发布时间】:2012-06-29 14:51:22
【问题描述】:

有人知道如何在 Postgresql 中执行这样的查询吗?

SELECT * 
FROM tabA 
WHERE NOT EXISTS (
    SELECT * 
    FROM tabB 
    WHERE tabB.id = tabA.id
)

当我执行这样的查询时,postgresql 报错“ERROR: Greenplum Database does not yet support that query。”

编辑:这个怎么样:

SELECT * 
FROM tabA 
WHERE NOT EXISTS (
    SELECT * 
    FROM tabB WHERE tabB.id = tabA.id AND tabB.id2 = tabA.id2
)

编辑:
我在 postgresql 8.2.15 中测试了@ypercube 提供的 4 个答案。结论是:

1)正如我在上面的问题中所说,第一个在这个版本的 postgresql 中不起作用。错误消息也可以在那里找到。

2)对于其他三个答案,执行速度为:(3)LEFT JOIN > (4)EXCEPT >> (2)NOT IN。
具体来说,对于语法相同的查询,(3)LEFT JOIN 大约需要 5580ms,(4)EXCEPT 大约需要 13502ms,(2)NOT IN 需要超过 100000(实际上我没有等待它完成)。
NOT IN 子句这么慢有什么特别的原因吗?

【问题讨论】:

  • PostgreSQL 8.2 已过时,不再受支持。从那时起,EXISTSNOT EXISTS 查询的工作方式发生了重大变化。 postgresql.org/support/versioning
  • 如果您想找到最有效的查询,我认为您首先必须检查表上的索引。您没有提到表的大小,但 5 秒的查询意味着(99%)要么是巨大的表,要么是缺少索引。我建议你添加一个新问题,包括两个表的定义(CREATE TABLE)、查询和执行计划。

标签: postgresql greenplum


【解决方案1】:

有 3 种(主要)方法可以进行这种查询:

  1. NOT EXISTS相关子查询

  2. NOT IN子查询

  3. LEFT JOINIS NULL 检查:

您发现第一种方法在 Greenplum 中确实有效。 @Marco 和 @juergen 提供了第二种方式。这是第 3 个,它可能会绕过 Greenplum 的限制:

SELECT tabA.* 
FROM 
    tabA 
  LEFT JOIN 
    tabB 
      ON  tabB.id = tabA.id 
      AND tabB.id2 = tabA.id2
WHERE tabB.id IS NULL ;

这(第 4 种方式)也适用于 Postgres(支持 EXCEPT 运算符):

SELECT a.*
FROM a
WHERE id IN
      ( SELECT id
        FROM a
      EXCEPT
        SELECT id
        FROM b
      ) ; 

SQL-Fiddle 中测试(所有 4 个都在 Postgres 中工作)。

【讨论】:

  • 不,它没有。我认为原因是在 LEFT JOIN 之前应用了过滤器“tabB.id IS NULL”,而不是在 LEFT JOIN 之后。
  • 如何在 NOT EXISTS 的情况下实现这个查询?你能提供任何帮助吗?
  • 正如错误所说,Greenplum“尚未”支持它。无法提供任何帮助。由于 NOT IN 查询有效,请使用它。
  • 假设我有两个表:UserInfo 和 UserOrder。我想找到没有订单的用户。此查询“SELECT * FROM UserInfo LEFT JOIN UserOrder ON UserInfo.userid = UserOrder.userid AND UserOrder.orderid IS NULL”返回 UserInfo 中的所有行。在我的表格中,UserOrder 中有确切的一行,而 UserInfo 中有不同用户的多行。
【解决方案2】:

您遗漏的部分错误可能会为您指明正确的方向。我认为它说“详细信息:查询包含相关子查询”。所以你必须用连接或不相关的子查询重写这些。

SELECT * FROM tabA WHERE id NOT IN (SELECT id FROM tabB);

至于第二个查询,试试

SELECT * FROM tabA WHERE (id, id2) NOT IN (SELECT id, id2 FROM tabB);

【讨论】:

  • 感谢您这么快回复。我更新了我的问题。新的查询呢?
  • 是的,它说“查询包含相关子查询”。 mysql直接支持这种查询。我认为postgresql也支持它。
  • postgres 有,有很多更复杂的东西,但 greenplum 没有,因为出于性能原因它必须放弃功能。
  • 无论如何,“SELECT * FROM tabA WHERE (id, id2) NOT IN (SELECT id, id2 FROM tabB)” 有效。谢谢。
【解决方案3】:
SELECT * FROM tabA 
WHERE id not in  (SELECT id FROM tabB)

【讨论】:

  • 我更新了我的问题,如何在 postgresql 中执行更新后的查询?
猜你喜欢
  • 2013-02-10
  • 2021-10-02
  • 2013-04-17
  • 2018-02-15
  • 1970-01-01
  • 2019-05-18
  • 2014-07-05
  • 2022-01-13
  • 1970-01-01
相关资源
最近更新 更多