Kurz gesagt
Für einen CSV-Import in PostgreSQL gibt es drei gängige Wege: der schnelle Server-Befehl COPY, sein lokales Gegenstück \copy in psql und der portable Weg über INSERT-Statements. Für eine Datei auf dem eigenen Rechner ist \copy meist am einfachsten, COPY ist am schnellsten für große Mengen, und INSERT-Statements sind ideal, wenn Sie ein sauberes Schema mit passenden Datentypen brauchen. Wichtig sind in allen Fällen das richtige Trennzeichen, das Encoding und die NULL-Behandlung.
CSV in PostgreSQL importieren: drei Wege im Überblick
Wer eine CSV-Datei in PostgreSQL importieren will, stösst schnell auf mehrere Methoden, die sich auf den ersten Blick ähneln, sich im Detail aber deutlich unterscheiden. Welcher Weg der richtige ist, hängt vor allem von einer Frage ab: Liegt die Datei auf dem Datenbankserver oder auf Ihrem eigenen Computer? Und brauchen Sie maximale Geschwindigkeit oder ein sauberes, versionierbares Schema?
Der schnellste Weg ist der SQL-Befehl COPY. Er liest eine Datei, die auf dem Server liegt, direkt in eine Tabelle ein und ist für große Datenmengen unschlagbar performant. Der Haken: PostgreSQL sucht die Datei im Dateisystem des Servers, nicht auf Ihrem Laptop. Genau dafür gibt es \copy, einen Meta-Befehl des Kommandozeilenwerkzeugs psql. Er liest die Datei vom lokalen Rechner und schiebt sie über die bestehende Datenbankverbindung. Für Alltagsfälle ist das meistens der bequemste Weg.
Der dritte Weg führt über INSERT-Statements: ein Stück SQL, das die Tabelle anlegt und Zeile für Zeile einfügt. Das ist langsamer als COPY, dafür völlig unabhängig von Dateipfaden und Serverrechten. Es lässt sich in eine Datenbank-Migration einchecken, per E-Mail verschicken oder in jeder Umgebung ausführen, in der Sie SQL absetzen können. Wenn Sie zusätzlich ein sauberes Schema mit erkannten Datentypen wollen, ist das oft die angenehmste Lösung. Mehr zum grundsätzlichen Vorgehen lesen Sie im Ratgeber CSV in SQL umwandeln.
| Methode | Datei liegt | Stärke |
|---|---|---|
| COPY | auf dem Server | sehr schnell, große Mengen |
| \copy (psql) | lokal beim Nutzer | bequem, keine Serverrechte nötig |
| INSERT-Statements | egal (reines SQL) | portabel, versionierbar, sauberes Schema |
| pgAdmin-Assistent | lokal beim Nutzer | grafisch, kein Befehl nötig |
Schritt 1: Zieltabelle anlegen
Anders als manche grafischen Tools legt PostgreSQL bei COPY die Tabelle nicht automatisch an. Die Zieltabelle muss bereits existieren und ihre Spalten müssen zur CSV passen, sowohl in der Reihenfolge als auch in der Anzahl. Das ist kein Nachteil, sondern eine Gelegenheit: Sie bestimmen selbst, welche Spalte welchen Datentyp bekommt.
Angenommen, Ihre CSV enthält eine Kundenliste mit Name, E-Mail, Anmeldedatum und Umsatz. Eine passende Tabelle könnte so aussehen:
CREATE TABLE kunden (
id SERIAL PRIMARY KEY,
name VARCHAR(120) NOT NULL,
email VARCHAR(160),
angemeldet DATE,
umsatz NUMERIC(10,2)
);
Die Wahl der Datentypen ist der wichtigste Schritt überhaupt. NUMERIC statt FLOAT für Geldbeträge vermeidet Rundungsfehler, DATE für ein reines Datum spart Speicher, und VARCHAR mit Längenbegrenzung dokumentiert Ihre Erwartung. Eine typische Falle: Felder, die nur aus Ziffern bestehen, aber keine echten Zahlen sind, etwa Postleitzahlen oder Artikelnummern mit führender Null. Wer dafür INTEGER wählt, verliert die führende Null. Solche Spalten gehören in eine Textspalte. Welche Typen sich aus welchen CSV-Werten ableiten lassen, behandelt der Ratgeber Datentypen aus CSV erkennen im Detail.
Wenn Sie sich das Schreiben des Schemas sparen möchten, erzeugt der CSV-zu-SQL-Konverter auf csv-sql.de das passende CREATE TABLE samt erkannten Datentypen automatisch im PostgreSQL-Dialekt, vollständig lokal in Ihrem Browser. Den Aufbau eines solchen CREATE TABLE erklärt der Ratgeber CREATE TABLE aus CSV generieren.
Schritt 2: Import mit COPY und \copy
Steht die Tabelle, kommt der eigentliche Import. Liegt die Datei auf dem Datenbankserver und haben Sie die nötigen Rechte, nutzen Sie den SQL-Befehl COPY:
COPY kunden (name, email, angemeldet, umsatz)
FROM '/var/lib/postgresql/import/kunden.csv'
WITH (FORMAT csv, HEADER true, DELIMITER ',', ENCODING 'UTF8');
Jede Option ist wichtig. FORMAT csv aktiviert die korrekte Behandlung von Anführungszeichen und eingebetteten Trennzeichen. HEADER true überspringt die erste Zeile mit den Spaltennamen, sonst landet sie als Datensatz in der Tabelle. DELIMITER legt das Trennzeichen fest, und ENCODING stellt sicher, dass Umlaute richtig ankommen. Die explizite Spaltenliste in Klammern ist Pflicht, wenn die CSV-Reihenfolge von der Tabelle abweicht oder Sie die automatisch vergebene id-Spalte überspringen wollen.
Das Problem an COPY: Es läuft mit den Rechten des Datenbankprozesses und sucht die Datei im Dateisystem des Servers. Auf einem gehosteten PostgreSQL, etwa bei einem Cloud-Anbieter, haben Sie dort oft gar keinen Zugriff. Genau dann ist \copy die Lösung. Es ist kein SQL, sondern ein psql-Befehl, der die Datei lokal liest:
\copy kunden (name, email, angemeldet, umsatz) \
FROM 'C:\Daten\kunden.csv' \
WITH (FORMAT csv, HEADER true, DELIMITER ';', ENCODING 'WIN1252')
Beachten Sie hier zwei Dinge: Der Pfad zeigt auf Ihren eigenen Rechner, und das Trennzeichen ist auf ; gesetzt, denn dieses Beispiel stammt aus deutschem Excel. Das Semikolon ist eine der häufigsten Stolperfallen beim CSV-Import überhaupt. Warum deutsches Excel anders trennt und wie Sie es zuverlässig lösen, erklärt der Ratgeber CSV mit Semikolon in SQL.
Soll ein leeres CSV-Feld als NULL ankommen und nicht als leere Zeichenkette, ergänzen Sie die Option NULL ''. Das ist gerade bei Datums- und Zahlenspalten wichtig, in die eine leere Zeichenkette ohnehin nicht passt.
Variante: Import per INSERT-Statements
Manchmal ist COPY nicht praktikabel: Sie haben keinen Dateizugriff, arbeiten in einer eingeschränkten Umgebung oder wollen die Daten in eine Migration einchecken, damit Kollegen denselben Stand erhalten. Dann sind INSERT-Statements der richtige Weg. Ein vollständiges Skript besteht aus dem CREATE TABLE und einer Reihe von INSERT-Befehlen:
INSERT INTO kunden (name, email, angemeldet, umsatz) VALUES
('Anja Wolters', 'anja@example.de', '2026-01-15', 1240.50),
('Tobias Reinke', 'tobias@example.de', '2026-02-03', 89.00),
('Lena Brandt', NULL, '2026-02-20', 540.75);
Diese Form, mehrere Zeilen in einem INSERT zusammengefasst, nennt sich Batch-INSERT und ist deutlich schneller als ein eigener INSERT pro Zeile. Trotzdem bleibt sie langsamer als COPY, weshalb sie für sehr große Datenmengen weniger geeignet ist. Für ein paar hundert oder tausend Zeilen merken Sie den Unterschied kaum.
Der entscheidende Sicherheitsaspekt ist das Escaping. Enthält ein Wert ein Apostroph, etwa ein Firmenname wie O'Brien GmbH, muss das Apostroph in SQL verdoppelt werden (O''Brien), sonst bricht das Statement oder öffnet im schlimmsten Fall eine Lücke für SQL-Injection. Wie Sie Sonderzeichen, Umlaute und Apostrophe sicher behandeln, erklärt der Ratgeber CSV-Werte sicher escapen.
Genau hier liegt die Stärke eines Generators: Der CSV-zu-SQL-Konverter auf csv-sql.de verdoppelt Apostrophe automatisch, formatiert Zahlen und Datumswerte korrekt, setzt leere Felder auf NULL und erzeugt das Ganze im PostgreSQL-Dialekt, ohne dass Ihre Datei jemals den Browser verlässt. Das Ergebnis kopieren Sie direkt in psql oder pgAdmin und führen es aus. Eine ausführliche Anleitung dazu finden Sie im Ratgeber INSERT-Statements aus CSV erzeugen.
Variante: Import mit pgAdmin
Wer lieber grafisch arbeitet, nutzt den Import-Assistenten von pgAdmin, dem offiziellen Verwaltungswerkzeug für PostgreSQL. Der Ablauf ist überschaubar:
- Legen Sie die Zieltabelle vorher an, denn auch pgAdmin importiert in eine bestehende Tabelle.
- Klicken Sie im Baum mit der rechten Maustaste auf die Tabelle und wählen Import/Export Data.
- Wählen Sie Import, die CSV-Datei, das Format csv und setzen Sie den Haken bei Header, falls die erste Zeile Spaltennamen enthält.
- Stellen Sie unter den Optionen das richtige Trennzeichen und die Kodierung ein, gerade bei deutschem Excel meist Semikolon und Windows-1252.
- Starten Sie den Import und prüfen Sie anschließend das Ergebnis.
Im Hintergrund nutzt pgAdmin nichts anderes als COPY. Der Assistent ist nur eine grafische Hülle, was bedeutet: Dieselben Regeln zu Trennzeichen, Kopfzeile und Encoding gelten genauso. Wer den Befehl versteht, versteht auch den Assistenten.
Schritt 3: Import prüfen
Ein Import ist erst dann erfolgreich, wenn die Daten auch korrekt angekommen sind. Drei kurze Abfragen geben Sicherheit. Zuerst die Zeilenzahl, sie muss zur CSV passen (abzüglich der Kopfzeile):
SELECT count(*) FROM kunden; Danach ein Blick auf die ersten Zeilen, um Umlaute, Datumsformate und Zahlen zu kontrollieren:
SELECT * FROM kunden LIMIT 5;
Sehen die Umlaute richtig aus, stimmt die Zeilenzahl und sind Datumswerte als Datum erkannt, ist der Import sauber. Erscheinen stattdessen Zeichen wie ü statt ü, war das Encoding falsch gesetzt. Landet die gesamte Zeile in einer einzigen Spalte, stimmt das Trennzeichen nicht.
Häufige Fehler und ihre Ursachen
Die meisten Probleme beim CSV-Import in PostgreSQL lassen sich auf eine Handvoll Ursachen zurückführen. Wer sie kennt, spart sich viel Sucherei.
- Alles in einer Spalte: Das Trennzeichen passt nicht. Deutsches Excel nutzt fast immer Semikolon, geben Sie
DELIMITER ';'an. - Kaputte Umlaute: Encoding-Konflikt. Die Datei ist Windows-1252, PostgreSQL erwartet UTF-8. Setzen Sie
ENCODING 'WIN1252'oder speichern Sie die CSV als UTF-8. - invalid input syntax for type: Eine Spalte enthält Werte, die nicht zum Datentyp passen, etwa Text in einer NUMERIC-Spalte oder ein deutsches Datum (31.12.2026) in einer DATE-Spalte, die ISO erwartet. Passen Sie den Typ an oder bereinigen Sie die Daten.
- permission denied beim COPY: Der Serverprozess darf die Datei nicht lesen oder sie liegt gar nicht auf dem Server. Nutzen Sie stattdessen
\copy. - Leere Felder als leerer String statt NULL: Standardverhalten von COPY. Ergänzen Sie
NULL '', wenn leere Felder zu NULL werden sollen. - Eine Zeile zu viel: Die Kopfzeile wurde als Datensatz importiert. Setzen Sie
HEADER true.
Wenn Sie wiederholt mit Datentyp- und Escaping-Problemen kämpfen, lohnt sich der Umweg über sauber generierte INSERT-Statements. Der Generator übernimmt Typ-Erkennung, NULL-Behandlung und Escaping in einem Schritt, und Sie sehen das fertige SQL, bevor Sie es ausführen. Ob ein Tool oder ein eigenes Skript besser passt, vergleicht der Ratgeber CSV in SQL mit Python umwandeln.
Häufige Fragen
Was ist der Unterschied zwischen COPY und \copy in PostgreSQL?
COPY ist ein SQL-Befehl, der auf dem Datenbankserver läuft und die Datei dort sucht, weshalb er Dateirechte und meist erweiterte Berechtigungen braucht. \copy ist ein Meta-Befehl von psql, der die Datei vom lokalen Rechner liest und über die bestehende Verbindung sendet. Für eine CSV auf dem eigenen Computer ist \copy fast immer der richtige Weg.
Wie importiere ich eine CSV mit Semikolon als Trennzeichen?
Deutsches Excel speichert CSV oft mit Semikolon statt Komma. Geben Sie das Trennzeichen explizit an, zum Beispiel DELIMITER ';'. Stimmt das Trennzeichen nicht, landet die gesamte Zeile in einer einzigen Spalte oder der Import bricht ab.
Warum erscheinen Umlaute beim CSV-Import als kaputte Zeichen?
Das ist fast immer ein Encoding-Problem. Excel speichert CSV häufig als Windows-1252 oder Latin-1, PostgreSQL erwartet standardmäßig UTF-8. Geben Sie beim Import die richtige Kodierung an, etwa ENCODING 'WIN1252', oder speichern Sie die Datei vorher als UTF-8.
Wie behandelt PostgreSQL leere Felder beim CSV-Import?
Standardmäßig wird ein leeres CSV-Feld bei COPY als leere Zeichenkette interpretiert, nicht als NULL. Soll ein leeres Feld als NULL ankommen, setzen Sie die Option NULL '' oder bereinigen die Daten vorher. Bei Textspalten ist der Unterschied wichtig, da leerer String und NULL nicht dasselbe sind.
Wann ist der Import per INSERT-Statements sinnvoller als COPY?
INSERT-Statements sind langsamer als COPY, aber praktisch, wenn Sie keinen Dateizugriff auf dem Server haben, die Daten in eine Migration einchecken oder das CSV erst in ein sauberes Schema mit korrekten Datentypen überführen wollen. Ein Konverter wie csv-sql.de erzeugt diese INSERT-Statements samt passendem CREATE TABLE direkt im Browser.