10

我已經寫了使用CTE的「更新插入」查詢看起來是這樣的:PostgreSQL的 - 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,但是我很好奇看看是否有單一查詢方式。

回答

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正在進行的同時插入行,它將會失敗。

+0

謝謝伊戈爾,我確實對「聯盟」感到疑惑,而且這看起來確實有效。儘管這會導致'更新'查詢運行兩次嗎? (我對CTE的理解有點不穩定,但我猜他們只運行一次並記住了?) – connec

+0

另外,您能否詳細說明您的陳述「順便提一下,此查詢不是經典的Postgres upsert」?這是很多被稱爲CTE驅動的upserts的查詢的時尚。 – connec

+2

@connec:「公共表」運行*一次*,結果在內部工作表中實現。 –