PostgreSQL - CTE upsert返回修改的行

时间:2013-07-10 16:00:58

标签: sql postgresql postgresql-9.1 common-table-expression upsert

我使用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
  )

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

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

编辑:当然我可以在交易中运行此跟随SELECT,但我很想知道是否有单一查询方式。

1 个答案:

答案 0 :(得分: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 

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