【问题标题】:PostgreSQL - CTE upsert returning modified rowsPostgreSQL - CTE upsert 返回修改的行
【发布时间】:2013-07-08 16:03:22
【问题描述】:

我使用 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,但是我很想知道是否有单一查询方式。

【问题讨论】:

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


    【解决方案1】:

    尝试类似:

    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 
    

    顺便说一句,这个查询不是经典的 Postgres upsert。如果有人在 UPDATE table t 进行时同时插入行,它将失败。

    【讨论】:

    • 感谢 Igor,我确实想知道 UNION,这似乎确实有效。但是,这会导致“更新”查询运行两次吗? (我对 CTE 的理解有点不稳定,但我猜它们只运行过一次就被记住了?)
    • 另外,您能否详细说明您的陈述“顺便说一句,此查询不是经典的 Postgres upsert”?这是许多声称是 CTE 驱动的 upsert 查询的时尚。
    • @connec:“公用表”运行一次,结果在内部工作表中实现。
    • @connec 阅读this 问题的答案和cmets。此 CTE 在高度并发的环境中可能会失败。 (但失败的可能性很低)
    猜你喜欢
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    • 2020-07-22
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多