PostgreSQL - CTE upsert возвращает измененные строки
Я написал запрос 'upsert', используя 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 *
в конец вставки вернет все строки, которые были вставлены, но ни одна из строк, которые были обновлены.
Итак, вопрос в том, как я могу расширить это, чтобы вернуть обновленные строки и строки, которые были вставлены?
EDIT: конечно, я мог бы запустить это, за которым следует SELECT
в транзакции, однако мне любопытно посмотреть, есть ли способ с одним запросом.
Ответы
Ответ 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
.