Skip to content

Eine Zeile upsen (INSERT oder UPDATE in einem Statement) snippet

Ein Upsert fügt die Zeile ein, wenn sie nicht existiert, und aktualisiert sie, wenn sie es tut — in EINEM Statement, ohne Read-then-Write-Race.

Ein Upsert fügt die Zeile ein, wenn sie nicht existiert, und aktualisiert sie, wenn sie es tut — in EINEM Statement, ohne Read-then-Write-Race. Der naive Zwei-Schritt (SELECT, dann INSERT oder UPDATE) korrumpiert unter Nebenläufigkeit Daten: Zwei Writer verpassen beide das SELECT und inserten beide. ON CONFLICT ist die Postgres-Antwort; MySQL schreibt es ON DUPLICATE KEY UPDATE, und SQLite kopiert die Postgres-Syntax. Zwei Dinge entscheiden über Korrektheit: Das Conflict-Ziel muss ein echter Unique Constraint oder Primary Key sein, und DO UPDATE braucht die Pseudo-Tabelle excluded.*, um die Werte zu lesen, deren Insert scheiterte.

Runnable recipe · 1 languages
Files & Datasqlupsertinserton-conflictpostgres

Every language

1 languages, copy-ready. One at a time with syntax highlighting, or all inline.

SQLSQLrunnable
INSERT INTO users (id, email, name)
VALUES (42, 'ada@example.com', 'Ada')
ON CONFLICT (id) DO UPDATE
    SET email = excluded.email,
        name  = excluded.name
RETURNING id, (xmax = 0) AS inserted_this_time;

excluded holds the row that failed to insert — read the challenger's values from it, not from the table. ON CONFLICT DO NOTHING is the ignore-duplicates variant. Run it twice in the playground: first pass inserts (true), second pass updates (false).

Run in the SQL playground →

Keep going

Read the database-objects cheatsheet →