Menu

SQLite: CSV importieren mit .import und --csv

So importierst du CSV-Dateien in SQLite mit dem .import-Befehl – inklusive Header, bestehender Tabellen, eigener Trennzeichen und der typischen Stolperfallen.

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

CSV-Import läuft über die CLI, nicht über SQL

In SQLites SQL-Dialekt gibt es kein IMPORT-Statement. Das Laden von CSV-Dateien ist eine Funktion der sqlite3-Kommandozeile — genauer gesagt ein Dot-Command namens .import. Wer von MySQLs LOAD DATA INFILE oder Postgres' COPY kommt, muss hier umdenken: Die laufen auf dem Server, während .import Sache des Client-Tools ist. Es liest die Datei selbst ein und feuert im Hintergrund passende INSERT-Statements ab.

Alles auf dieser Seite setzt also voraus, dass du in der sqlite3-Shell bist:

sqlite3 mydata.db

Wenn du den Import lieber aus deinem Anwendungscode heraus erledigen willst — sei es Python, Node oder Go —, liest du die CSV-Datei in deiner Sprache ein und schickst die Daten über parametrisierte INSERT-Statements an die Datenbank. Diesen Weg schauen wir uns im Kapitel zur Anwendungsintegration genauer an. Hier bleiben wir bei der CLI.

Der einfachste Weg: csv in sqlite importieren mit .import

Der kürzeste Weg: Sag SQLite, dass es sich um eine CSV-Datei handelt, und übergib dem .import-Befehl den Dateipfad sowie den Tabellennamen.

.mode csv
.import people.csv people

Was passiert, hängt davon ab, ob die Tabelle people schon existiert:

  • Tabelle existiert nicht — SQLite legt sie an und nimmt die erste Zeile der CSV als Spaltennamen. Jede Spalte bekommt die Affinität TEXT.
  • Tabelle existiert bereits — SQLite fügt jede Zeile der Datei als Daten ein. Die Kopfzeile landet, falls vorhanden, ebenfalls als ganz normale Datenzeile in der Tabelle.

Genau der zweite Fall ist die Stolperfalle, in die fast jeder beim ersten Versuch tappt. Hat deine CSV eine Kopfzeile und die Zieltabelle steht schon, musst du diese Zeile ausdrücklich überspringen.

Kopfzeile beim Import in eine bestehende Tabelle überspringen

Mit --skip 1 sagst du .import, dass die ersten N Zeilen ignoriert werden sollen:

CREATE TABLE people (
    name TEXT,
    age  INTEGER,
    city TEXT
);

.import --csv --skip 1 people.csv people

--csv ist die Kurzform für .mode csv, die nur für diesen einen Befehl gilt – du musst den Modus also nicht separat setzen. Mit --skip 1 überspringst du die Kopfzeile. Die restlichen Zeilen landen in der Reihenfolge der Spalten in people.

Ein kurzer Check nach dem Import:

SELECT count(*) FROM people;
SELECT * FROM people LIMIT 5;

Die Reihenfolge der Spalten in der Datei muss exakt zur Spaltenreihenfolge in der Tabelle passen. Ein Mapping über die Header-Namen gibt es nicht – .import ordnet einfach das N-te Feld der N-ten Spalte zu.

Tabelle automatisch von SQLite erstellen lassen

Beim Herumprobieren ist es am bequemsten, das CREATE TABLE komplett wegzulassen und die Tabelle direkt von .import aus dem Header der CSV-Datei anlegen zu lassen:

.mode csv
.import sales.csv sales

.schema sales

.schema sales zeigt dir dann etwa Folgendes:

CREATE TABLE sales(
  "order_id" TEXT,
  "amount" TEXT,
  "ordered_at" TEXT
);

Beachte, dass jede Spalte den Typ TEXT hat. Das ist Absicht — .import versucht gar nicht erst, Typen zu erraten. Wenn du amount als echte Zahl und ordered_at als richtigen Zeitstempel haben willst, lege die Tabelle vorher selbst mit den passenden Typen an und importiere dann mit --skip 1. Beim Einfügen sorgt die Type Affinity von SQLite dafür, dass numerische Strings in Integer- und Real-Werte umgewandelt werden.

Andere Trennzeichen: TSV, Pipe, Semikolon

.mode csv verwendet das Komma als Trennzeichen. Für tab-getrennte Dateien wechselst du den Modus:

.mode tabs
.import data.tsv events

Bei anderen Trennzeichen setzt du .separator nach der Wahl des Modus:

.mode csv
.separator "|"
.import pipe_data.txt events

Wichtig zu wissen: .mode csv hält sich an die Quoting-Regeln aus RFC 4180 — Felder mit Kommas oder Zeilenumbrüchen funktionieren also problemlos, solange sie sauber mit " umschlossen sind. .mode tabs ist dagegen ein simpler Split-Modus auf ein bestimmtes Zeichen, ganz ohne Quoting. Wenn deine Datei also Felder in Anführungszeichen mit eingebetteten Trennzeichen enthält, bleib bei .mode csv und passe stattdessen das Trennzeichen an.

Praxisbeispiel: CSV in SQLite importieren

Nehmen wir an, orders.csv sieht so aus:

order_id,customer,amount,ordered_at
1001,Ada,49.99,2026-01-12
1002,Boris,12.50,2026-01-13
1003,"Chen, Wei",199.00,2026-01-14

Beachte, dass Zeile 3 ein Komma innerhalb eines Anführungszeichen-Felds enthält. Hier ist die komplette Session:

In einer echten Shell würde der INSERT-Block durch einen einzigen Aufruf von .import --csv --skip 1 orders.csv orders ersetzt. Das Feld "Chen, Wei" bleibt dabei unversehrt, weil der CSV-Modus die Anführungszeichen respektiert. amount landet dank der Spaltentypen als echte Zahl in der Datenbank und order_id als Integer.

CSV-Import in eine Transaktion verpacken

.import setzt pro Zeile ein eigenes INSERT ab. Bei ein paar tausend Zeilen ist das kein Problem. Bei einer Million wird's allerdings quälend langsam – es sei denn, du packst den gesamten Import in eine Transaktion, damit SQLite nicht nach jeder einzelnen Zeile committet:

BEGIN;
.import --csv --skip 1 big_file.csv events
COMMIT;

Mit dieser einen Anpassung wird aus einem mehrminütigen Import eine Sache von Sekunden. Sollte mittendrin etwas schiefgehen, macht ROLLBACK den teilweisen Import rückgängig — praktisch, wenn du es noch mal versuchen willst.

Noch schneller wird's, wenn du Indizes vor dem Import entfernst und danach neu anlegst. Die Index-Pflege pro Zeile summiert sich nämlich gewaltig.

Typische Fehler beim CSV-Import und wie du sie löst

Error: expected N columns but found M — die Spaltenzahl einer Zeile passt nicht zur Tabelle. Übliche Ursachen:

  • Ein verirrtes Komma in einem nicht-quotierten Feld. Exportiere die Datei mit sauberem CSV-Quoting noch mal neu, oder wechsle von .mode tabs auf .mode csv (RFC 4180).
  • Eine leere Zeile am Dateiende. Entferne sie aus der Datei oder nutze --skip kreativ.
  • Die Tabelle hat mehr Spalten als die CSV-Datei. Entweder ergänzt du die fehlenden Spalten in der Datei oder du importierst in eine Staging-Tabelle mit passender Struktur und schiebst die Daten dann in die eigentliche Tabelle.

Die Kopfzeile landet als Datensatz — du hast --skip 1 bei einer bestehenden Tabelle vergessen. Lösch die Zeile (DELETE FROM t WHERE rowid = 1) und starte den Import mit dem Flag erneut.

Zahlen werden als Strings gespeichert — du hast .import die Tabelle anlegen lassen, dadurch ist jede Spalte vom Typ TEXT. Lösche die Tabelle, definiere sie explizit mit INTEGER/REAL-Spalten und importiere noch mal.

Error: no such file — der Pfad ist relativ zum Verzeichnis, in dem du sqlite3 gestartet hast, nicht zur Datenbankdatei. Nimm einen absoluten Pfad oder wechsle vorher per cd ins richtige Verzeichnis.

Bei Fehlern gibt die CLI die Zeilennummer aus — der schnellste Weg, die problematische Zeile in einer großen Datei zu finden.

Kurz zusammengefasst

  • .import ist ein CLI-Dot-Command, kein SQL. Du führst es innerhalb der sqlite3-Shell aus.
  • Mit --csv wird das Quoting korrekt behandelt, mit --skip 1 ignorierst du die Kopfzeile.
  • Existiert die Tabelle nicht, legt .import sie anhand der Header an — alle Spalten landen aber als TEXT. Für saubere Datentypen erstellst du die Tabelle besser selbst.
  • Pack große Imports in BEGIN/COMMIT, sonst gibt es eine Transaktion pro Zeile.
  • Die Spaltenreihenfolge in der Datei muss zur Spaltenreihenfolge in der Tabelle passen.

Als Nächstes: Daten wieder exportieren

Importieren ist nur die halbe Miete. Dieselbe Shell kann Abfrageergebnisse oder ganze Tabellen auch wieder als CSV, JSON oder SQL ausgeben — nützlich für Backups, Datenpipelines und die Übergabe an andere Tools. Mehr dazu im nächsten Kapitel zum Datenexport.

Häufig gestellte Fragen

Wie importiere ich eine CSV-Datei in SQLite?

Öffne die Datenbank mit dem sqlite3-CLI, schalte mit .mode csv in den CSV-Modus und führe dann .import data.csv table_name aus. Existiert die Tabelle noch nicht, legt SQLite sie automatisch an und nimmt die erste Zeile der Datei als Spaltennamen. Existiert sie bereits, wird jede Zeile der Datei als Datensatz eingefügt – in dem Fall willst du in der Regel .import --skip 1 nutzen, damit der Header nicht als Datenzeile landet.

Wie lade ich eine CSV mit Header in eine bestehende SQLite-Tabelle?

Mit .import --csv --skip 1 data.csv table_name. Das Flag --skip 1 sorgt dafür, dass die erste Zeile ignoriert wird, sodass der Header nicht als Datensatz übernommen wird. Ohne das Flag bekommst du eine Zeile, in der wortwörtlich die Spaltennamen als Werte stehen.

Warum bricht mein CSV-Import mit 'expected N columns but found M' ab?

In der Datei gibt es Zeilen mit einer anderen Spaltenanzahl als die Tabelle erwartet – meist wegen Kommas im Text, nicht korrekt escapter Anführungszeichen oder einer leeren Zeile am Dateiende. Nutze .mode csv (oder --csv) statt .mode tabs, dann verarbeitet SQLite Anführungszeichen nach RFC 4180 sauber. Die CLI gibt dir außerdem die Zeilennummer aus, in der es klemmt – damit findest du die fehlerhafte Zeile am schnellsten.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S