Zum Inhalt
wannacode

Upsert: einfügen oder ändern

Kurz gesagt: Ein Upsert fügt eine Zeile ein oder ändert die schon vorhandene mit ON CONFLICT … DO UPDATE, wenn eine eindeutige Spalte verletzt wird; DO NOTHING überspringt den Konflikt.

Problem

Der Kunde kommt wieder

Georgi Petrov ist nach Sofia gezogen. Er bestellt, ohne sich anzumelden, und das Formular schickt seinen Namen, seine E-Mail-Adresse und seine Stadt. Die Website versucht, ihn als neuen Kunden zu speichern:

SQLDatenbank: Shop

Seine E-Mail-Adresse steht schon in der Datenbank, und sie ist eindeutig. Die Website muss entscheiden: neuer Kunde oder bestehender. Sie könnte erst mit einem SELECT prüfen und dann zwischen INSERT und UPDATE wählen. Aber das sind zwei Anweisungen, und dazwischen könnte ein anderer Besucher dieselbe E-Mail-Adresse speichern.

Die Idee

ON CONFLICT … DO UPDATE

ON CONFLICT sagt INSERT, was zu tun ist, wenn die Zeile eine eindeutige Spalte verletzt. Mit DO UPDATE ändert es die Zeile, die schon in der Tabelle steht:

SQLDatenbank: Shop

Die zwei Zeilen gehen verschiedene Wege. Georgi ist da: Seine Zeile behält die Nummer 2 und das Anmeldedatum von 2025, nur die Stadt ändert sich. Vesela ist nicht da: Sie wird als Kundin 21 eingefügt.

excluded ist die Zeile, die die Anweisung einfügen wollte. excluded.city ist die Stadt aus VALUES, und city ohne etwas davor ist der alte Wert in der Tabelle.

Das heißt Upsert, aus „update“ und „insert“.

Genauer, für Neugierige

In PostgreSQL ist die Anweisung dieselbe: ON CONFLICT (email) DO UPDATE SET city = EXCLUDED.city. MySQL hat eine eigene Form: INSERT … ON DUPLICATE KEY UPDATE. SQL Server und Oracle benutzen MERGE, einen allgemeineren Befehl, der zwei Tabellen vergleicht und für jede Zeile entscheidet: einfügen, ändern oder löschen. PostgreSQL hat MERGE seit Version 15. SQLite hat kein MERGE.

Probier es aus

Eine neue Adresse

Elena Dimitrova (elena.d@example.com) ist nach Varna gezogen. Das Formular schickt ihren Namen, ihre E-Mail-Adresse, die Stadt Varna und das heutige Datum, 2026-10-25. Speichere sie so, dass sich nur die Stadt ändert. Ihr Anmeldedatum bleibt das alte.

SQLDatenbank: Shop

Die Idee

Ware vom Lieferanten

Am Morgen kommt eine Lieferung: 30 Banitsas, 40 Gurken und ein neues Produkt, Ayran. Der Lieferant benutzt die Produktnummern des Shops, und der Ayran hat im Katalog schon die Nummer 26. Die bekannten Produkte müssen mehr Bestand bekommen, und das neue muss erscheinen:

SQLDatenbank: Shop

Der Konflikt liegt bei id, dem Primärschlüssel. Für die Banitsa und die Gurken addiert products.stock + excluded.stock den gelieferten Bestand zum alten. Ihr Datum added_at bleibt das alte, weil es nicht in SET steht. Den Ayran gibt es nicht, deshalb wird er mit allen Spalten eingefügt.

Hier steht vor stock ein products., weil der Ausdruck zwei Bestände hat: den in der Tabelle und den aus der Lieferung.

Probier es aus

Mehr im Warenkorb

Georgi legt 2 Packungen Butter (Produkt 9, 3,20 €) in seine neue Bestellung 57. Wenn sie schon drin ist, muss die Menge steigen, und wenn nicht, muss eine Zeile dazukommen.

SQLDatenbank: Shop

Sieh es dir an

DO NOTHING

Manchmal soll sich bei einem Konflikt nichts ändern. Von einer Messe kommt eine Liste von Leuten, die Kunden werden wollen. Wer schon Kunde ist, wird übersprungen:

SQLDatenbank: Shop

Maria bleibt, wie sie war, mit der Stadt Sofia. Vesela ist eine neue Kundin. Ohne ON CONFLICT hätte die ganze Anweisung bei Maria angehalten, und Vesela wäre nicht hineingekommen.

Genauer, für Neugierige

SQLite hat auch eine ältere eigene Form: INSERT OR IGNORE macht dasselbe wie DO NOTHING.

SQLDatenbank: Shop

INSERT OR REPLACE sieht aus wie ein Upsert, ist aber keins. Bei einem Konflikt löscht es die alte Zeile und fügt eine neue ein. Teodora bekommt eine neue Nummer und ein neues Anmeldedatum:

SQLDatenbank: Shop

Bei Georgi geht das Löschen gar nicht durch, weil seine Bestellungen auf die alte Zeile zeigen:

SQLDatenbank: Shop

Nimm für ein Upsert also ON CONFLICT … DO UPDATE. Es ändert nur die Spalten in SET.

Übung

Die Lieferung

Der Lieferant schickt die Lieferung als Tabelle delivery: Produktnummer, Name, Kategorie, Preis und Menge. Für die Lektion ist die Tabelle schon in der Datenbank. Führ das SELECT am Anfang aus, um sie zu sehen.

Speichere die Lieferung in products. Bei den bekannten Produkten wird die gelieferte Menge zum Bestand addiert und der Preis des Lieferanten übernommen. Die neuen werden mit dem Datum 2026-10-25 eingefügt.

Die Lieferung in products:

SQLDatenbank: Shop

Test

Teste dich

1. Was ist excluded in ON CONFLICT … DO UPDATE?
2. Wann kommt ON CONFLICT (email) ins Spiel?
3. Warum funktioniert ON CONFLICT (city) im Shop nicht?
4. Was ist in SQLite der Unterschied zwischen ON CONFLICT DO UPDATE und INSERT OR REPLACE?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·