Upsert in SQLite mit ON CONFLICT DO UPDATE
Einfügen oder aktualisieren in einem einzigen Statement – mit ON CONFLICT ... DO UPDATE. Kein vorheriges SELECT, kein Race Condition zwischen Prüfen und Schreiben.
„Wenn der Eintrag existiert, aktualisiere ihn, sonst füge ihn neu ein." Das nennt man Upsert. Statt erst mit einem SELECT zu prüfen und dann zu entscheiden, macht SQLite das atomar in einem Statement – mit ON CONFLICT ... DO UPDATE. Das spart nicht nur Code, sondern schließt auch die Lücke zwischen Prüfen und Schreiben, in der sonst zwei parallele Zugriffe kollidieren könnten.
Voraussetzung: ein Unique-Constraint
Ein Upsert braucht eine Spalte, an der SQLite den Konflikt erkennt – einen PRIMARY KEY oder UNIQUE-Index.
CREATE TABLE seiten_aufrufe (
pfad TEXT PRIMARY KEY,
treffer INTEGER NOT NULL DEFAULT 0,
zuletzt INTEGER NOT NULL
);Das Upsert
INSERT INTO seiten_aufrufe (pfad, treffer, zuletzt)
VALUES ('/start', 1, unixepoch())
ON CONFLICT(pfad) DO UPDATE SET
treffer = treffer + 1,
zuletzt = excluded.zuletzt;Der Clou ist das Schlüsselwort excluded: Es steht für die Zeile, die eingefügt werden sollte. So greifst du im UPDATE-Teil auf die neuen Werte zu – hier setze ich zuletzt auf den gerade übergebenen Zeitstempel, während ich treffer um eins hochzähle.
Nur bei Bedarf aktualisieren
Du kannst den Update-Teil zusätzlich an eine Bedingung knüpfen – etwa nur schreiben, wenn sich wirklich etwas ändert:
INSERT INTO seiten_aufrufe (pfad, treffer, zuletzt)
VALUES ('/start', 1, unixepoch())
ON CONFLICT(pfad) DO UPDATE SET
treffer = treffer + 1,
zuletzt = excluded.zuletzt
WHERE excluded.zuletzt > seiten_aufrufe.zuletzt;Genau dieses Muster nutze ich für die cookielose Aufruf-Statistik in meinem eigenen CMS. Wenn du eine Website mit sauberer, datensparsamer Auswertung brauchst, findest du mich auf bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Laufende Summe in SQL – SUM() OVER statt Schleife in der Anwendung
Kontostand nach jeder Buchung, kumulierter Umsatz im Jahr, Restbestand nach jeder Entnahme: Alles dieselbe Frage. Mit einer Fensterfunktion beantwortet die Datenbank sie in einer Abfrage – inklusive gleitendem Durchschnitt.
NULL in SQL – warum COUNT(spalte) lügt und wo die leeren Werte landen
NULL ist kein Wert, sondern die Abwesenheit eines Werts. Deshalb zählt COUNT(spalte) anders als COUNT(*), summiert SUM() an leeren Zeilen vorbei und landen beim Sortieren alle Lücken am selben Ende.
Wie viel mehr als gestern? Differenz zur Vorzeile mit LAG() in SQL
„Wie viele Besucher heute im Vergleich zu gestern?" – der Reflex ist ein Self-Join auf die Vorzeile. Mit der Fensterfunktion LAG() bekommst du den Wert der vorherigen Zeile direkt daneben, ohne die Tabelle ein zweites Mal anzufassen.