Menu

SQLite INSERT: Zeilen einfügen mit OR IGNORE & Bulk Insert

Wie INSERT in SQLite wirklich funktioniert: einzelne Zeilen, Mehrzeilen-Inserts, INSERT...SELECT, Default-Werte sowie die Konflikt-Modifizierer OR IGNORE und OR REPLACE.

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

Mit INSERT neue Zeilen in eine Tabelle einfügen

Mit INSERT schreibst du neue Zeilen in eine Tabelle. Der Aufbau ist kurz und immer gleich:

Drei Dinge solltest du dir hier merken:

  • INSERT INTO books — die Zieltabelle.
  • (title, author, year) — die Spalten, für die du Werte mitlieferst.
  • VALUES (...) — die Werte, in derselben Reihenfolge wie die Spaltenliste.

Die Spalte id taucht in der Liste nicht auf, also vergibt SQLite den Wert automatisch (sie ist als INTEGER PRIMARY KEY definiert und bekommt damit die rowid). Jede Spalte, die du weglässt, bekommt ihren Default-Wert — oder NULL, falls keiner definiert ist.

Spalten immer explizit angeben

Du kannst die Spaltenliste auch weglassen und stattdessen Werte für alle Spalten in der Reihenfolge ihrer Deklaration angeben:

-- Funktioniert, aber fragil:
INSERT INTO books VALUES (NULL, 'Dune', 'Frank Herbert', 1965);

Lass das. Sobald jemand eine Spalte zu books hinzufügt, fliegen dir solche Statements um die Ohren oder die Werte landen in den falschen Spalten. Schreib die Spalten lieber explizit aus:

Explizite Spaltenlisten sind eine Form von Dokumentation – das Statement lässt sich allein lesen, ohne dass man die Tabellendefinition nachschlagen muss.

Mehrere Zeilen gleichzeitig einfügen

Mit SQLite kannst du mehrere Zeilen in einem einzigen INSERT INTO-Statement einfügen, indem du einfach weitere Werte-Tupel anhängst:

Das ist sauberer als drei einzelne INSERT-Anweisungen, und SQLite behandelt das Ganze als ein einziges Statement. Den richtigen Performance-Schub bei größeren Datenmengen bekommst du aber erst, wenn du deine Inserts in eine Transaktion packst – dazu gleich mehr.

SQLite Bulk Insert: Ab in die Transaktion damit

Standardmäßig läuft jedes INSERT als eigene Transaktion. SQLite macht am Ende jeder Transaktion ein fsync, und genau das ist der Grund, warum naive Schleifen so langsam sind – nicht die Inserts an sich.

Fass sie zusammen:

Ein fsync statt fünf. Bei tausenden Zeilen kann der Unterschied zwei bis drei Größenordnungen ausmachen. Geht irgendwo zwischendrin etwas schief, macht ROLLBACK den kompletten Batch rückgängig.

Dieses Muster ist das Standardrezept für den SQLite Bulk Insert. Egal ob du SQLite aus Python, Node oder Rust ansprichst – pack deine Schleife immer in BEGIN / COMMIT ein.

INSERT ... SELECT: Daten aus einer anderen Tabelle übernehmen

Statt feste Werte zu übergeben, kannst du eine Tabelle auch direkt aus einer Abfrage befüllen:

Die Spalten aus dem SELECT werden anhand ihrer Position den Spalten in der Spaltenliste des INSERT zugeordnet. Die Namen müssen nicht übereinstimmen — entscheidend ist die Reihenfolge. Das ist der Standardweg, um Zeilen zu archivieren, Reporting-Tabellen aufzubauen oder bei einer Migration eine Teilmenge der Daten zu kopieren.

DEFAULT VALUES und ausgelassene Spalten

Hat eine Spalte eine DEFAULT-Klausel, kannst du sie einfach aus der Spaltenliste weglassen — SQLite trägt dann automatisch den Standardwert ein:

created_at bekommt automatisch den aktuellen Zeitstempel, weil wir keinen mitgegeben haben. Wenn du eine Zeile komplett mit Standardwerten anlegen willst – praktisch für Platzhalter-Einträge – nimm die DEFAULT VALUES-Variante:

Zwei neue Zeilen, beide mit value = 0 und automatisch vergebenen IDs.

INSERT OR IGNORE: Duplikate überspringen

Wenn eine Zeile gegen einen UNIQUE- oder PRIMARY KEY-Constraint verstößt, bricht SQLite das Statement standardmäßig mit einem Fehler ab:

Error: UNIQUE constraint failed: users.email

INSERT OR IGNORE ersetzt das durch „die betroffene Zeile einfach stillschweigend überspringen":

Drei Zeilen bleiben übrig. Der Duplikateintrag wird ohne Fehler verworfen. Genau so drückt man in SQLite idiomatisch ein „insert if not exists" für einfache Seed-Daten aus – ganz ohne vorgeschaltetes SELECT zur Prüfung und ohne Exception-Handling.

INSERT OR REPLACE: Duplikate überschreiben

INSERT OR REPLACE löscht die konfliktverursachende Zeile und fügt an ihrer Stelle die neue ein:

Achtung bei einer Sache: REPLACE ist DELETE + INSERT, nicht UPDATE. Wenn auf die gelöschte Zeile Fremdschlüssel mit ON DELETE CASCADE zeigen, werden die Kindzeilen gleich mitgelöscht. Und jede Spalte, die du im neuen INSERT nicht angibst, fällt auf ihren Default-Wert zurück – der alte Wert bleibt eben nicht erhalten.

Für die typischen Fälle nach dem Motto „aktualisieren, falls vorhanden, sonst einfügen" willst du eigentlich einen echten Upsert mit ON CONFLICT ... DO UPDATE. Dafür gibt es eine eigene Seite.

Kurze Zusammenfassung

  • INSERT INTO table (cols) VALUES (...) – die Grundform. Spalten immer explizit auflisten.
  • Mit sqlite insert into mehrere Zeilen einfügen: einfach kommagetrennte Tupel hinter VALUES.
  • Für richtigen sqlite bulk insert die Inserts in BEGIN / COMMIT einpacken.
  • INSERT INTO ... SELECT ... kopiert Zeilen aus einer Abfrage.
  • DEFAULT VALUES legt eine Zeile rein aus Default-Werten an; weggelassene Spalten greifen ebenfalls auf ihre Defaults zurück.
  • INSERT OR IGNORE überspringt konfliktbehaftete Zeilen, INSERT OR REPLACE überschreibt sie (über Delete + Insert).

Weiter geht's mit UPDATE

Zeilen einfügen ist nur die halbe Miete. Die andere Hälfte besteht darin, vorhandene Zeilen zu ändern – einen Zähler hochsetzen, einen Tippfehler korrigieren, eine Bestellung als versandt markieren. Genau dafür ist UPDATE da, und gerade rund um die WHERE-Klausel gibt es ein paar Eigenheiten, die man kennen sollte. Mehr dazu im nächsten Kapitel.

Häufig gestellte Fragen

Wie füge ich in SQLite eine Zeile ein?

Mit INSERT INTO tabelle (spalte1, spalte2) VALUES (wert1, wert2);. Die Spaltenliste ist zwar optional, sollte aber zur Routine werden — so funktioniert das Statement auch dann noch, wenn die Tabelle später eine zusätzliche Spalte bekommt. Lässt du die Liste weg, musst du für jede Spalte in Deklarationsreihenfolge einen Wert liefern.

Wie füge ich mehrere Zeilen auf einmal ein?

Hänge einfach mehrere Wertetupel hinter VALUES, durch Kommas getrennt: INSERT INTO t (a, b) VALUES (1, 2), (3, 4), (5, 6);. Bei echten Massenimports (tausende Zeilen) packst du die Inserts zusätzlich in eine einzelne Transaktion mit BEGIN und COMMIT — der eigentliche Speed-Boost kommt nämlich daher, nicht von der Mehrzeilen-Syntax selbst.

Was macht INSERT OR IGNORE in SQLite?

INSERT OR IGNORE überspringt Zeilen, die einen UNIQUE-, PRIMARY KEY- oder NOT NULL-Constraint verletzen würden, statt einen Fehler zu werfen. Die kollidierende Zeile wird stillschweigend verworfen, der Rest des Statements läuft weiter durch. Praktisch, wenn du ein 'einfügen, falls noch nicht vorhanden' ohne vorherige Existenzprüfung haben willst.

Warum bekomme ich beim INSERT 'UNIQUE constraint failed'?

SQLite hat bereits eine Zeile mit demselben Wert in einer UNIQUE- oder PRIMARY KEY-Spalte gefunden. Entweder ist der Wert tatsächlich ein Duplikat, oder du lässt gerade ein Seed-Skript erneut laufen. Lösung: INSERT OR IGNORE, wenn du Duplikate überspringen willst, INSERT OR REPLACE, um sie zu überschreiben, oder ON CONFLICT ... DO UPDATE (Upsert) für feinere Kontrolle.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S