11

次のような CTE を使用して「アップサート」クエリを作成しました。

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、単一クエリの方法があるかどうかを知りたいです。

4

1 に答える 1

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 

ところで、このクエリは従来の Postgres upsert ではありません。進行中に誰かが同時に行を挿入すると、失敗しUPDATE table tます。

于 2013-07-10T16:07:54.140 に答える