10

Ich habe eine ‚Upsert‘ query mit CTEs geschrieben, die etwa wie folgt aussieht:PostgreSQL - CTE Upsert geänderten Zeilen Rückkehr

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 
) 

Jedoch habe ich dann mit den neuen Werten in meiner Anwendung arbeiten müssen, aber dies Abfrage wird nichts zurückgeben. Wenn Sie am Ende der Einfügung returning * hinzufügen, werden alle Zeilen zurückgegeben, die eingefügt wurden, aber keine der Zeilen, die aktualisiert wurden.

Also ist die Frage (wie) kann ich dies erweitern, um die Zeilen, die aktualisiert wurden UND die Zeilen, die eingefügt wurden, zurückzugeben?

EDIT: natürlich könnte ich diese gefolgt von einer SELECT in einer Transaktion ausführen, aber ich bin gespannt, ob es eine Single-Abfrage Weg ist.

Antwort

9

Versuchen Sie so etwas wie:

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 diese Abfrage ist kein klassisches Postgres Upsert. Es wird fehlschlagen, wenn jemand Zeilen gleichzeitig einfügt, während UPDATE table t geht.

+0

Dank Igor, ich habe mich über "UNION" wundern, und das scheint tatsächlich zu funktionieren. Wird dies dazu führen, dass die "aktualisierte" Abfrage zweimal ausgeführt wird? (Mein Verständnis von CTEs ist ein wenig wackelig, aber ich denke, sie sind einmal ausgeführt und erinnerte sich?) – connec

+0

Könnten Sie auch auf Ihre Aussage "BTW diese Abfrage ist keine klassische Postgres Upsert" näher ausführen? Dies ist die Mode vieler Abfragen, die angeblich CTE-getriebene Upserts sind. – connec

+2

@connec: "gemeinsame Tabellen" werden einmal * ausgeführt und das Ergebnis wird in einer internen Arbeitstabelle materialisiert. –