mygems

Mehrere CSV-Dateien zu einer zusammenführen

Zusammenhängen ordnet Spalten nach Position zu, ein anderer Header ruiniert das Ergebnis still. So führst du nach Spaltennamen zusammen und prüfst es.

Von uos ·

Wenn die Dateien identische Spalten in identischer Reihenfolge haben, ist der schnellste korrekte Weg ein Shell-Einzeiler, der den ersten Header behält und alle anderen weglässt:

head -n 1 first.csv > merged.csv
tail -q -n +2 *.csv >> merged.csv

Alles andere auf dieser Seite gibt es, weil die Annahme identischer Spalten in identischer Reihenfolge viel öfter nicht stimmt, als man denkt, und der Fehler bleibt unbemerkt. Ein Merge, der zwei Spalten verschiebt, liefert eine Datei, die sich problemlos öffnen lässt, gut aussieht und trotzdem falsch ist.

Zuerst prüfen, ob die Header übereinstimmen

Mach das vor dem Zusammenführen, nicht danach. Jedes weitere Problem ist eine Variante dieses einen.

for f in *.csv; do echo "$f: $(head -n 1 "$f")"; done

Achte in der Ausgabe auf vier Dinge:

  • Andere Spaltenreihenfolge. name,email,date in der einen Datei und name,date,email in der anderen. Beim Aneinanderhängen landen Datumswerte in der E-Mail-Spalte, und nichts beschwert sich.
  • Verschiedene Namen für dasselbe Feld. Email, email, E-mail, Email Address. Typisch, wenn die Dateien aus verschiedenen Exporten stammen oder derselbe Export in verschiedenen Jahren gemacht wurde.
  • Zusätzliche oder fehlende Spalten. Ein späterer Export hat ein Feld dazubekommen. Die Zeilen sind jetzt unterschiedlich breit.
  • Ein Byte Order Mark (BOM) in der ersten Datei. §BOM§name ist nicht name. Es ist in jedem Editor unsichtbar und bricht Joins über Spaltennamen.

Sind alle Header byteidentisch, nimm die Zweizeilen-Variante oben und hör auf zu lesen. Wenn nicht, ist Aneinanderhängen das falsche Werkzeug, und du brauchst etwas, das nach Spaltenname zusammenführt.

Nach Spaltenname zusammenführen

DuckDB, wenn die Dateien groß sind oder die Header abweichen

Ein Befehl löst beide Probleme, abweichende Spaltenreihenfolge und fehlende Spalten, weil er nach Name statt nach Position ausrichtet:

duckdb -c "COPY (SELECT * FROM read_csv('*.csv', union_by_name=true, filename=true)) TO 'merged.csv' (HEADER)"

union_by_name=true leistet die eigentliche Arbeit: Spalten werden über den Header zugeordnet, und eine Datei ohne eine bestimmte Spalte bekommt dafür NULL, statt dass die Zeile verrutscht. filename=true fügt eine Spalte hinzu, die festhält, aus welcher Datei jede Zeile stammt. Die wirst du öfter brauchen, als du denkst. Nur so lässt sich im Nachhinein beantworten, in welchem Export eine fehlerhafte Zeile angekommen ist.

DuckDB streamt, die Dateigröße wird also durch die Festplatte begrenzt, nicht durch den Arbeitsspeicher. Hundert Dateien mit zusammen mehreren Gigabyte sind nichts Besonderes.

Python, wenn du die Namen erst angleichen musst

Wenn dasselbe Feld in einer Datei Email und in einer anderen E-mail Address heißt, kann kein Werkzeug das erraten. Vereinheitliche ausdrücklich:

import glob, pandas as pd

rename = {"E-mail Address": "email", "Email": "email"}
frames = []
for path in glob.glob("*.csv"):
    df = pd.read_csv(path, dtype=str)
    df.columns = [c.strip().lstrip("§BOM§") for c in df.columns]
    frames.append(df.rename(columns=rename).assign(source=path))

pd.concat(frames, ignore_index=True).to_csv("merged.csv", index=False)

Zwei Details sind wichtiger als der Merge selbst. dtype=str verhindert, dass pandas die Typen pro Datei errät. Ohne das kommt eine Kunden-ID-Spalte, die in einer Datei numerisch und in einer anderen alphanumerisch ist, als Mischung aus 1024 und "01024" heraus, und die führenden Nullen sind für immer weg. Und .assign(source=path) ist dieselbe Herkunftsspalte, die DuckDB dir geschenkt liefert.

Power Query, auf dem Desktop ohne Terminal

In Excel zeigt Daten → Daten abrufen → Aus Ordner auf ein Verzeichnis und kombiniert alle Dateien darin, zugeordnet über den Header. Das kann es gut, es aktualisiert sich, wenn neue Dateien im Ordner landen, und es ist die richtige Antwort für alle, die diesen Merge jeden Monat wiederholen.

Seine Grenze ist die Grenze von Excel: Das Ergebnis muss in 1.048.576 Zeilen passen, um auf einem Blatt zu landen. Du kannst stattdessen ins Datenmodell laden und das Blatt ganz auslassen, was die meisten nicht wissen und was die Grenze deutlich anhebt.

Anhängen oder verknüpfen

„Zusammenführen“ meint zwei verschiedene Operationen, und mit der falschen verschwendest du einen Nachmittag.

Du hastDu willstOperation
Zwölf Monatsexporte, gleiche SpaltenEine Datei, mehr ZeilenAnhängen (Append, stapeln)
Kunden in einer Datei, Bestellungen in einer anderenEine Datei, mehr SpaltenJoin (über einen Schlüssel verknüpfen)

Alles oben ist Anhängen. Ein Join braucht einen gemeinsamen Schlüssel und eine Entscheidung, was mit Zeilen ohne Treffer passiert, und genau hier entstehen Duplikate: Ein Schlüssel, der auf beiden Seiten nicht eindeutig ist, vervielfacht Zeilen unbemerkt. Wenn die Zeilenzahl nach einem Join größer ist als bei beiden Eingaben, ist das passiert.

Für einen Join ist SQL das ehrliche Werkzeug:

duckdb -c "COPY (SELECT c.*, o.order_total FROM read_csv('customers.csv') c LEFT JOIN read_csv('orders.csv') o USING (customer_id)) TO 'merged.csv' (HEADER)"

Auf dem Smartphone

Das realistische Smartphone-Szenario: eine Handvoll Dateien in Mail oder Dateien, drei regionale Exporte oder ein paar Monate Kontoauszüge, und bis Montag kein Laptop.

Zwei Dinge helfen hier. Dateien mit identischen Headern anzuhängen ist Kopieren und Einfügen, vorausgesetzt die App kann einen Zeilenblock einfügen statt nur eine Zelle nach der anderen. Und die wichtige Prüfung, der Header-Vergleich, geht am Smartphone schneller als irgendwo sonst: jede Datei öffnen, die oberste Zeile lesen.

CSV Editor - Smart CSViPhone & iPad

Öffnet jeden Export in Sekunden, fügt einen Zeilenbereich in ein anderes Blatt ein und schreibt beim Speichern jede Zeile zurück, auch in der kostenlosen Version. Dank Spalten- und Zeilen-Einfügen ist es echtes Bearbeiten statt Notlösung, eine Datei abzugleichen, die ein Feld dazubekommen hat.

Was es kann

Bei mehr als einer Handvoll Dateien warte auf einen Desktop. Dreißig Exporte von Hand auf einem Touchscreen zusammenzuführen ist keine gute Idee, und der Grund ist die Fehlerquote, nicht die Mühe.

Nach dem Merge: vier Prüfungen

Mach sie jedes Mal. Sie dauern eine Minute und fangen praktisch jeden relevanten Merge-Fehler ab.

  1. Zeilenanzahl. Die Summe im Ergebnis sollte der Summe aller Eingaben entsprechen, minus ein Header pro Datei. wc -l *.csv vorher, wc -l merged.csv nachher.
  2. Header-Anzahl. grep -c "^name," merged.csv oder wie auch immer die erste Spalte heißt. Mehr als einer bedeutet, dass ein Header als Datenzeile gelandet ist.
  3. Spaltenbreite. Jede Zeile sollte gleich viele Felder haben. Ungleiche Breiten deuten auf ein nicht maskiertes Komma hin, nicht auf einen Merge-Fehler.
  4. Die Nahtstelle prüfen. Schau dir im Ergebnis die letzte Zeile der ersten und die erste Zeile der zweiten Datei an. Verschiebungen fallen dort zuerst auf.

Die zweite Prüfung hat eine Feinheit: Landet eine Header-Zeile in den Daten, verteilt sie das Sortieren mitten in die Datei, und später ist sie sehr schwer zu finden. Fang das jetzt ab.

CSV File Viewer - Smart CSViPhone & iPad · Android

Führt SQL direkt auf der zusammengeführten Datei aus. Ein GROUP BY auf die Quellspalte zeigt dir, dass jede Datei so viele Zeilen beigetragen hat wie erwartet, die ganze Verifikation in einer Abfrage.

Was es kann

Kodierung, der Fehler, der jede Prüfung überlebt

Dateien aus verschiedenen Systemen haben oft verschiedene Kodierungen, und Aneinanderhängen konvertiert nichts. Eine UTF-8-Datei, die an eine Windows-1252-Datei angehängt wird, ergibt eine Datei, die keins von beiden ist: Namen sehen in der ersten Hälfte richtig aus und in der zweiten als é.

Konvertiere vor dem Zusammenführen, nicht danach:

iconv -f WINDOWS-1252 -t UTF-8 old.csv > old-utf8.csv

file -I *.csv rät, was du vor dir hast, liegt bei kurzen Dateien aber oft daneben. Verlässlich ist nur, jede Datei zu öffnen und eine Zeile mit einem Nicht-ASCII-Zeichen anzusehen.

Fragen

Wie füge ich mehrere CSV-Dateien zu einer zusammen?
Wenn alle Dateien byteidentische Header haben, behalte den ersten Header und hänge den Rest an: `head -n 1 first.csv > merged.csv` und dann `tail -q -n +2 *.csv >> merged.csv`. Unterscheiden sich die Header in Reihenfolge oder Inhalt, verschiebt das Aneinanderhängen die Spalten unbemerkt. Nimm dann ein Werkzeug, das nach Spaltenname zuordnet, etwa DuckDBs read_csv mit union_by_name=true oder Excels „Aus Ordner“.
Warum stehen die Spalten in meiner zusammengeführten CSV an der falschen Stelle?
Weil das Aneinanderhängen nach Position zuordnet, nicht nach Name. Zwei Dateien mit denselben Spalten in anderer Reihenfolge ergeben eine Datei mit verschobenen Werten, und es wird kein Fehler gemeldet. Vergleiche vor dem Zusammenführen immer die Header-Zeilen: `for f in *.csv; do echo "$f: $(head -n 1 "$f")"; done`.
Wie führe ich CSV-Dateien mit unterschiedlichen Spalten zusammen?
Ordne nach Spaltenname zu und fülle die Lücken. DuckDB macht das mit `union_by_name=true` in einem Befehl und liefert NULL für eine Spalte, die eine Datei nicht hat. In pandas leistet `pd.concat` auf Frames, die mit `dtype=str` gelesen wurden, dasselbe. Felder, die dasselbe meinen, aber anders heißen, etwa Email und E-mail Address, musst du vorher ausdrücklich umbenennen; das kann kein Werkzeug erraten.
Woher weiß ich, aus welcher Datei jede Zeile der zusammengeführten CSV stammt?
Füge beim Zusammenführen eine Herkunftsspalte hinzu. DuckDBs read_csv kennt `filename=true` und fügt sie automatisch ein; in pandas macht `.assign(source=path)` pro Frame dasselbe. Nur so lässt sich eine fehlerhafte Zeile später zu ihrem Export zurückverfolgen, und die Prüfung wird zu einem einzigen GROUP BY.
Woher weiß ich, dass das Zusammenführen der CSV geklappt hat?
Vier Prüfungen: Die Zeilenanzahl entspricht der Summe der Eingaben minus ein Header pro Datei; die Header-Zeichenkette kommt genau einmal vor; jede Zeile hat gleich viele Felder; und der Übergang zwischen erster und zweiter Datei sieht richtig aus. Ein Header, der als Datenzeile gelandet ist, ist der Fehler, den man früh finden sollte, denn Sortieren verteilt ihn mitten in die Datei.
Warum sind Umlaute und Akzente in der Hälfte meiner zusammengeführten Datei kaputt?
Die Eingaben hatten unterschiedliche Kodierungen, und Anhängen konvertiert nichts. Eine Windows-1252-Datei an einer UTF-8-Datei ergibt in der einen Hälfte korrekte Namen und in der anderen Zeichensalat (Mojibake). Konvertiere zuerst alles nach UTF-8 mit `iconv -f WINDOWS-1252 -t UTF-8 old.csv > old-utf8.csv` und führe dann zusammen.

uos — Baut CSV Editor und Smart CSV Viewer und hat erlebt, wie ein Merge 200.000 Zeilen lang eine Spalte um eine Position verschob, ohne einen einzigen Fehler.