【问题标题】:Postgres: correlated subquery with NOT EXISTSPostgres:不存在的相关子查询
【发布时间】:2014-05-11 15:00:00
【问题描述】:

在 Oracle SQL 中,您可以轻松地根据相关子查询中的 NOT EXISTS 条件进行更新。这对于基于另一个查询或 id 列表进行更新很有用。

Postgres 中子查询的机制不同……我怎样才能达到相同的目标? http://sqlfiddle.com/#!1/1dbb8/55

您将如何在 Oracle 上做到这一点

UPDATE UserInfo a
SET a.username = 'not found'
WHERE NOT EXISTS (SELECT 'X' 
              FROM UserOrder b
              WHERE b.userid = a.userid)
AND a.userid in (1,2,3);

Postgres NOT EXISTS 查询:可行

SELECT u.userid, u.username
FROM UserInfo AS u
WHERE NOT EXISTS
  ( SELECT *
    FROM UserOrder AS o
    WHERE o.userid = u.userid
);

Postgres NOT EXISTS 更新:不起作用

UPDATE UserInfo
SET username = 'not found'
FROM (SELECT u.userid
    FROM UserInfo AS u
    WHERE NOT EXISTS
       ( SELECT *
         FROM UserOrder AS o
         WHERE o.userid = u.userid
       )) em
WHERE em.userid = UserInfo.userid;

【问题讨论】:

  • 所以你想更新一个左反连接的左边?在 Pg 中,您可以执行此操作,但不幸的是,它需要在左侧进行自连接,例如update t1 ... from t1 a left outer join ... on ... where t.id = t1.id,因为除了针对更新目标表的 inner join(impicit,通过 update ... from)之外,没有任何支持。
  • 给定的解决方案有效。考虑一下updated fiddle

标签: sql oracle postgresql


【解决方案1】:

显然,每次“运行脚本”时,Sqlfiddle 都会重新生成数据库内容。在与更新相同的脚本中运行选择。

您从 sqlfiddle 进行的 Oracle 查询几乎可以正常工作,但是您忘记为 userid 参数设置别名。正确查询:

/* How you would do it on Oracle */
UPDATE UserInfo
SET username = 'not found'
WHERE NOT EXISTS (SELECT 'X' 
                  FROM UserOrder b
                  WHERE b.userid = userinfo.userid);

【讨论】:

    【解决方案2】:
    UPDATE UserInfo a
    SET username = 'not found'
    WHERE NOT EXISTS (
          SELECT 'X' 
          FROM UserOrder b
          WHERE b.userid = a.userid
          )
    AND a.userid in (1,2,3)
      ;
    

    绝对应该在 Postgres 中工作。

    【讨论】:

    • 对不起,我也不能让它在 SQL 小提琴中工作。
    【解决方案3】:

    你为什么让update 比原来的选择更复杂。这段代码应该在 Postgres 和 Oracle 中都可以工作:

    UPDATE UserInfo ui
      SET username = 'not found'
      WHERE NOT EXISTS (SELECT 'X' 
                        FROM UserOrder uo
                        WHERE uo.userid = ui.userid
                       ) AND
            ui.userid in (1,2,3);
    

    问题是SET ui.username。 Postgres 不允许在set 子句中使用表别名(因为您一次只能更新一个表)。

    嵌套相关子查询存在“问题”。它适用于某些数据库,但不适用于其他数据库。我知道它在 SQL Server 中有效,在 MySQL 和 Oracle 中无效。我想它在 Postgres 中也不起作用。

    【讨论】:

    • 这就是我的想法,但是这个 SQL 更新了零行。在 SQLfiddle 中尝试一下,看看我的意思。
    • @ardochhigh 。 . .当我在你的 SQL Fiddle 中尝试它时,它可以工作。你可以在这里看到:sqlfiddle.com/#!1/b36ae/1
    猜你喜欢
    • 2021-03-25
    • 2021-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    相关资源
    最近更新 更多