【问题标题】:Cannot SELECT from UPDATE RETURNING clause in postgres无法从 postgres 中的 UPDATE RETURNING 子句中选择
【发布时间】:2011-08-25 14:13:48
【问题描述】:

我将问题与更复杂的查询隔离开来。这里是测试场景

DROP TABLE test; 
CREATE TABLE test (
  id integer,
  description varchar(100)
);

INSERT INTO test(id, description) VALUES (1,'new'); 
INSERT INTO test(id, description) VALUES (2,'new'); 

如果我运行查询:

SELECT * FROM test WHERE id IN (UPDATE test set description='test' RETURNING id)

我收到以下错误:

错误:“测试”处或附近的语法错误 LINE 1: SELECT * FROM test WHERE id (UPDATE test set description='test' RE... ^

***费勒 ***

错误:“测试”处或附近的语法错误 SQL 状态:42601 泽臣:37

但是,如果我只运行语句

UPDATE test set value='test' RETURNING id

我得到 2 行的结果:

1 2

如果我替换该结果,我会得到如下查询:

SELECT * FROM test WHERE id IN (1,2);

结果:

1;“测试” 2;“测试”

为什么我的初始语句没有得到相同的结果?

【问题讨论】:

  • 它们必须是单独的语句。两行正在更新这一事实可能会导致问题,当不止一行/值返回时,从未尝试过 RETURNING。

标签: sql postgresql


【解决方案1】:

在 PostgreSQL 9.1 之前,INSERT/UPDATE/DELETE 只能用作顶级语句。这就是您收到语法错误的原因。

从 9.1 开始,您可以将数据修改语句与公用表表达式一起使用。您的示例查询如下所示:

WITH updated AS (UPDATE test SET description = 'test' RETURNING id)
SELECT * FROM test WHERE id IN (SELECT id FROM updated);

小心从刚刚修改的表格中进行选择。这样你会得到令人困惑的结果。因为查询是在同一个快照中执行的,所以 SELECT 不会看到 UPDATE 语句的效果。

【讨论】:

  • 所以这个SELECT会返回id和旧的描述值'new'而不是更新的值'test'
【解决方案2】:

您在UPDATE 查询中更新两行,添加WHERE 子句以限制受影响的行。

UPDATE test SET description = 'test' WHERE id = 1 RETURNING id

返回单行

【讨论】:

  • SELECT * FROM test WHERE id IN (UPDATE test SET value='test' WHERE id=1 TURNING id) 显示同样的错误
【解决方案3】:
UPDATE test set description='test' RETURNING *

会为您提供初始查询所期望的结果集。

但我怀疑你在尝试更复杂的东西?

【讨论】:

    【解决方案4】:

    您是否缺少IN:... WHERE id IN (UPDATE ...

    但是,如果我只运行语句“UPDATE test set value='test' RETURNING id",我得到一个有 2 行的结果。为什么会这样?

    您的UPDATE 没有WHERE 子句,因此它会更新每一行,其中有两行。

    【讨论】:

    • 问题不在于更新 RETURNING,而是使用和不使用 where 子句。问题在于它周围的选择。
    【解决方案5】:

    你没有限制你的 where 子句。你需要有 id = (blahblah) 或 id IN (blahblah)

    【讨论】:

      【解决方案6】:
      DROP TABLE IF EXISTS test_tab;
      
      CREATE TABLE test_tab (
        id integer,
        description varchar(100)
      );
      
      INSERT INTO test_tab(id, description) VALUES (1,'new'); 
      INSERT INTO test_tab(id, description) VALUES (2,'new'); 
      
      SELECT * from test_tab;
      
      DO $$
      DECLARE
          myID    test_tab.id%TYPE;
          testID  test_tab.id%TYPE;
          cur_IDs CURSOR for select id from test_tab;
      BEGIN
          OPEN cur_IDs;
          LOOP
              FETCH cur_IDs into testID;
              EXIT WHEN testID is NULL;
      
              UPDATE test_tab SET description='test' WHERE id = testID RETURNING id into myID;
              raise notice 'myID %', myID;
          END LOOP;
          CLOSE cur_IDs;
      END$$;
      
      
      DROP TABLE IF EXISTS test_tab;
      

      【讨论】:

        【解决方案7】:

        我是来自 Ants Aasma,如果在同一张桌子上选择,使用:

        WITH updated AS (UPDATE test SET description = 'test' RETURNING id, description)
        SELECT * FROM updated;
        

        【讨论】:

          猜你喜欢
          • 2017-05-03
          • 2014-12-13
          • 2011-02-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-09-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多