Menu

SQLite UNIQUE Constraint: Spalten, Composite Keys & NULL

So funktioniert die UNIQUE-Einschränkung in SQLite: auf Spalten- und Tabellenebene, mit zusammengesetzten Schlüsseln, dem NULL-Sonderfall und Tipps, wenn der Constraint einmal fehlschlägt.

Diese Seite enthält ausführbare Editoren — bearbeiten, ausführen und Ausgabe sofort sehen.

UNIQUE bedeutet: keine Duplikate erlaubt

Ein UNIQUE-Constraint sagt SQLite, dass Werte in einer Spalte (oder einer Gruppe von Spalten) sich über die Zeilen hinweg nicht wiederholen dürfen. Genau damit drückst du aus: "Zwei Benutzer dürfen sich nicht dieselbe E-Mail teilen" oder "Ein Produktcode kommt höchstens einmal vor."

Der dritte INSERT scheitert mit UNIQUE constraint failed: users.email. SQLite prüft den Constraint bei jedem Schreibvorgang und blockt alles ab, was einen Duplikat-Eintrag erzeugen würde. Die ersten beiden Zeilen landen sauber in der Tabelle, die dritte kommt gar nicht erst durch.

Unter der Haube wird UNIQUE über einen Unique Index abgebildet — also exakt die Datenstruktur, die SQLite ohnehin für schnelle Lookups nutzt. Die Prüfung ist dadurch günstig, und die Spalte ist automatisch indiziert.

UNIQUE auf Spaltenebene vs. Tabellenebene

Für UNIQUE gibt es zwei Schreibweisen: entweder direkt hinter der Spalte (inline) oder als eigene Klausel am Ende der Tabellendefinition:

Bei einer einzelnen Spalte sind beide Varianten gleichwertig – nimm einfach die, die sich besser liest. Sobald die Eindeutigkeit aber über mehrere Spalten hinweg gelten soll, führt an der Schreibweise auf Tabellenebene kein Weg vorbei.

Composite UNIQUE Key in SQLite: Eindeutigkeit über mehrere Spalten

Manchmal ist eine einzelne Spalte für sich genommen nicht eindeutig – aber eine Kombination aus Spalten soll es sein. Ein Nutzer kann sich in viele Kurse einschreiben, und ein Kurs kann viele Nutzer haben. Dasselbe Paar (user_id, course_id) darf in der Tabelle aber kein zweites Mal auftauchen:

Die Einschränkung greift auf das Paar, nicht auf eine einzelne Spalte. Nutzer 1 darf sich in viele Kurse einschreiben, Kurs 100 darf viele Nutzer haben – aber jede Kombination eben nur einmal.

Genau dieses Muster brauchst du ständig für Join-Tabellen bei Many-to-Many-Beziehungen.

SQLite UNIQUE vs PRIMARY KEY

Die beiden klingen ähnlich und sind verwandt, aber sie sind nicht dasselbe:

  • Eine Tabelle hat höchstens einen PRIMARY KEY, kann aber beliebig viele UNIQUE-Constraints haben.
  • Der PRIMARY KEY ist die Identität der Zeile – darauf zeigen Foreign Keys, und er ist der Alias für die rowid.
  • UNIQUE heißt schlicht: „dieser Wert (oder diese Kombination) kommt nicht doppelt vor".
  • In einer normalen Tabelle darf eine UNIQUE-Spalte NULL-Werte enthalten, ein PRIMARY KEY nicht (von einer historischen Ausnahme sehen wir hier ab).

Ein typisches Muster sieht so aus:

id ist das, worauf der Rest der Datenbank verweist. email und username sind nur deshalb mit einem UNIQUE-Constraint versehen, weil die Anwendung das verlangt – nicht, weil sie die Identität abbilden. Wenn ein Nutzer seine E-Mail-Adresse ändert, bleibt die id dieselbe. Genau darum trennt man die beiden.

Die Sache mit NULL in SQLite

Über diese Eigenheit stolpert wirklich jeder beim ersten Mal. Eine UNIQUE-Spalte in SQLite erlaubt beliebig viele NULL-Werte:

Drei NULLs sind kein Problem. Zwei 'ada@example.com' dagegen schon – Konflikt.

Der Grund: In SQL gilt NULL als "unbekannt", und zwei unbekannte Werte gelten nicht als gleich. Die Unique-Prüfung kann sie also gar nicht als Duplikate erkennen. Wenn du höchstens ein NULL zulassen willst, ist NOT NULL UNIQUE die sauberste Lösung. Falls NULLs erlaubt sein sollen, aber nur eines pro Kombination der übrigen Spalten, brauchst du einen Partial Index (kommt später im Kapitel zu Indizes).

Konflikte abfangen mit ON CONFLICT

Standardmäßig bricht SQLite das Statement bei einer UNIQUE-Verletzung ab. Manchmal willst du aber ein anderes Verhalten: die bestehende Zeile ersetzen, den neuen Datensatz ignorieren oder gezielt einzelne Spalten aktualisieren. Dafür bietet dir SQLite zwei Wege an.

Der erste baut das Verhalten direkt in den Constraint ein, mit ON CONFLICT:

Beim zweiten Einfügen von theme wird die vorhandene Zeile gelöscht und durch die neue ersetzt. Weitere Optionen sind IGNORE (still überspringen), ABORT (Standardverhalten), FAIL und ROLLBACK.

Die zweite Variante arbeitet pro Statement über die Upsert-Syntax — meist flexibler, weil sich damit gezielt einzelne Spalten aktualisieren lassen:

Der erste INSERT legt die Zeile an. Die beiden folgenden laufen in den UNIQUE-Constraint und landen dadurch im DO UPDATE-Zweig, der count hochzählt. Genau das ist das Upsert-Muster mit INSERT ... ON CONFLICT — dazu gibt es weiter hinten noch eine eigene Seite.

UNIQUE Constraint vs. UNIQUE Index

CREATE UNIQUE INDEX macht im Grunde dasselbe wie ein UNIQUE-Constraint. Tatsächlich legt ein UNIQUE-Constraint im Hintergrund automatisch einen Unique Index an — es ist also derselbe Mechanismus, nur mit einem anderen Hut auf.

Wann sollte man was nehmen:

  • Constraint, wenn die Eindeutigkeit fester Bestandteil der Tabellendefinition ist. Sie steht dann direkt neben den Spalten und ist damit selbstdokumentierend.
  • Unique Index, wenn du einen Partial Index brauchst (mit WHERE-Klausel), einen bestimmten Namen vergeben willst oder die Regel zu einer bestehenden Tabelle hinzufügen möchtest, ohne sie neu aufzubauen. ALTER TABLE kann in SQLite zwar kein Constraint nachträglich anhängen, aber einen Index nachzurüsten geht immer.

Beim Schreiben verhalten sich beide Varianten identisch. Die Entscheidung ist also vor allem eine Frage davon, wo die Regel im Schema verankert sein soll.

UNIQUE nachträglich zu einer bestehenden Tabelle hinzufügen

ALTER TABLE ist in SQLite bewusst eingeschränkt — ein ALTER TABLE ... ADD CONSTRAINT gibt es schlicht nicht. Bleiben dir zwei praktikable Wege:

Variante 2 – wenn du die UNIQUE-Klausel unbedingt direkt in der Tabellendefinition haben willst – läuft auf den klassischen Tabellen-Umbau hinaus: neue Tabelle mit Constraint anlegen, Daten rüberkopieren, alte Tabelle löschen, umbenennen. Wie das geht, zeigt die nächste Seite.

Ein Hinweis am Rande: Wenn du eine Spalte nachträglich eindeutig machen willst, in der schon Duplikate stehen, schlägt CREATE UNIQUE INDEX fehl. Räum also erst die doppelten Zeilen auf und leg dann den Index an.

sqlite unique constraint failed: Fehlermeldung richtig lesen

Die Fehlermeldung verrät dir auf den Punkt genau, welcher Constraint verletzt wurde:

Error: UNIQUE constraint failed: users.email
Error: UNIQUE constraint failed: enrollments.user_id, enrollments.course_id

Die erste Variante ist ein UNIQUE-Constraint auf einer einzelnen Spalte (users.email). Die zweite ist ein zusammengesetzter Constraint (Composite Unique Key) — beide Spalten tauchen auf, weil die Kombination bereits existiert. Wenn du also einen sqlite unique constraint failed-Fehler siehst:

  1. Finde heraus, welche Zeile den kollidierenden Wert schon hat (SELECT ... WHERE email = '...').
  2. Entscheide, ob du diese Zeile aktualisieren, das Insert überspringen oder einen anderen Wert verwenden willst.
  3. Sind Duplikate erwartet und du möchtest zusammenführen, greif zu INSERT ... ON CONFLICT DO UPDATE.

Der Fehler ist bewusst laut, denn meistens willst du genau das wissen — stille Duplikate wären schlimmer als ein fehlgeschlagener Schreibvorgang.

Als Nächstes: Tabellen löschen und ändern

Ein UNIQUE-Constraint lässt sich an einer bestehenden Tabelle nicht einfach per ALTER TABLE nachrüsten. Genau wegen dieser Einschränkung hat SQLite seinen eigenen Tanz für Schemaänderungen — das sogenannte Table-Rewrite-Verfahren. Darum geht es auf der nächsten Seite, zusammen mit den Grundlagen, wie du Tabellen sauber wieder loswirst.

Häufig gestellte Fragen

Wie lege ich in SQLite eine UNIQUE-Einschränkung an?

Entweder direkt an der Spalte (email TEXT UNIQUE) oder auf Tabellenebene mit UNIQUE(col1, col2), wenn die Kombination mehrerer Spalten eindeutig sein soll. SQLite legt im Hintergrund automatisch einen Unique-Index an und weist jedes INSERT oder UPDATE zurück, das ein Duplikat erzeugen würde.

Was ist der Unterschied zwischen UNIQUE und PRIMARY KEY in SQLite?

Pro Tabelle ist nur ein PRIMARY KEY erlaubt, aber beliebig viele UNIQUE-Constraints. Der Primärschlüssel impliziert zudem NOT NULL (in STRICT-Tabellen sowie bei INTEGER PRIMARY KEY), während UNIQUE-Spalten mehrere NULL-Werte enthalten dürfen. Faustregel: PRIMARY KEY für die Identität der Zeile, UNIQUE für alle anderen Spalten, die nicht doppelt vorkommen sollen.

Warum erlaubt SQLite mehrere NULL-Werte in einer UNIQUE-Spalte?

Weil SQL NULL als 'unbekannt' interpretiert – und zwei unbekannte Werte gelten nicht als gleich. Eine UNIQUE-Spalte akzeptiert deshalb beliebig viele NULL-Zeilen; nur die nicht-NULL-Werte müssen eindeutig sein. Soll höchstens ein NULL erlaubt sein, ergänzt man NOT NULL oder verwendet einen partiellen Unique-Index.

Wie behebe ich den Fehler 'UNIQUE constraint failed'?

Die Meldung bedeutet, dass ein INSERT oder UPDATE einen doppelten Wert in einer UNIQUE- oder PRIMARY KEY-Spalte erzeugt hätte. Lösungswege: den einzufügenden Wert ändern, den bestehenden Datensatz vorher löschen oder per INSERT ... ON CONFLICT (Upsert) explizit festlegen, was SQLite im Konfliktfall tun soll.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S