PostgreSQL - CTE upsert返回修改的行

con*_*nec 11 sql postgresql upsert common-table-expression postgresql-9.1

我用CTE写了一个'upsert'查询,看起来像这样:

WITH
  new_data (id, value) AS (
    VALUES (1, 2), (3, 4), ...
  ),
  updated AS (
    UPDATE table t set
      value = t.value + new_data.value
    FROM new_data
    WHERE t.id = new_data.id
    RETURNING t.*
  )
INSERT INTO table (id, value)
  SELECT id, value
  FROM new_data
  WHERE NOT EXISTS (
    SELECT 1 FROM updated WHERE updated.id = new_data.id
  )
Run Code Online (Sandbox Code Playgroud)

但是,我需要在我的应用程序中使用新值,但此查询不会返回任何内容.添加returning *到插入的末尾将返回已插入的所有行,但不会返回任何已更新的行.

那么,问题是(如何)我可以扩展它以返回已更新的行和插入的行?

编辑:当然我可以SELECT在一个事务中运行它然后运行,但我很想知道是否有单查询方式.

Igo*_*nko 9

尝试类似的东西:

WITH
  new_data (id, value) AS (
    VALUES (1, 2), (3, 4), ...
  ),
  updated AS (
    UPDATE table t set
      value = t.value + new_data.value
    FROM new_data
    WHERE t.id = new_data.id
    RETURNING t.*
  ),
  inserted as (
  INSERT INTO table (id, value)
  SELECT id, value
  FROM new_data
  WHERE NOT EXISTS (
    SELECT 1 FROM updated WHERE updated.id = new_data.id
  )
  RETURNING id, value)
SELECT id, value
FROM inserted 
UNION ALL
SELECT id, value
FROM updated 
Run Code Online (Sandbox Code Playgroud)

BTW这个查询不是经典的Postgres upsert.如果有人在进行时同时插入行,它将失败UPDATE table t.

  • @connec:"公共表"运行*一次*,结果在内部工作表中实现. (2认同)
  • @connec阅读[`this`](http://stackoverflow.com/questions/1109061/insert-on-duplicate-update-postgresql)问题的答案和评论.此CTE可能在严重并发环境中失败.(但失败的因素很低) (2认同)