CSV-Exporte von Banken sind auf immer die gleiche Art widerspenstig. Wer die Liste kennt, macht aus einer verwirrenden Datei eine Aufgabe für fünf Minuten. Jedes der folgenden Probleme ist eine Formatierungsentscheidung der Bank und kein Schaden an der Datei:
- Kopfzeilen vor der Tabelle. Kontoname, Bankleitzahl (Sort Code), Zeitraum und eine Leerzeile vor der eigentlichen Kopfzeile. Jeder Parser, den du auf die Datei loslässt, hält die erste dieser Zeilen für die Spaltennamen.
- Zwei Betragsspalten,
DebitundCredit, statt eines einzigen Betrags mit Vorzeichen. Oder ein Betrag mit Vorzeichen, bei dem die Vorzeichenlogik das Gegenteil von dem ist, was du erwartest. - Mehrdeutige Datumsangaben.
03/04/2026ist in Großbritannien der 3. April und in den USA der 4. März, und die Datei verrät nicht, was gemeint ist. - Eine Beschreibungsspalte, die fünf Felder auf einmal enthält: Händler, Ort, Kartennummer, Verwendungszweck und die bankeigene Buchungsart.
- Beträge als Text, mit Tausendertrennzeichen, Währungssymbolen oder Negativwerten in der Form
(45.00).
Behebst du diese fünf Punkte, sind es ganz normale Daten.
Zuerst die Struktur klären
Öffne die Datei und sieh dir als Erstes die ersten zehn Zeilen an:
head -n 12 statement.csv
Zähle die Kopfzeilen und finde heraus, welche Zeile die echte Kopfzeile ist. Dann überspringst du sie:
tail -n +5 statement.csv > clean.csv
Öffnest du die Datei stattdessen in einer Tabellenkalkulation, lösche diese Zeilen, bevor du irgendetwas anderes tust. Sortierst oder filterst du mit ihnen, landet die Kontozusammenfassung mitten in deinen Buchungen. Dort fällt sie kaum auf und rutscht leicht in eine Summe.
Datumsangaben, die Falle
Dieser Fehler liefert falsche Ergebnisse statt eines offensichtlichen Defekts. Ein Parser im US-Format, der einen britischen Kontoauszug liest, macht stillschweigend aus dem 3. April den 4. März, und zwar für jeden Tag bis einschließlich zum Zwölften. Alle übrigen Tage lässt er in Ruhe. Das Ergebnis sieht völlig normal aus, und jede Monatssumme ist falsch.
Zwei Wege, das zu klären, nach Verlässlichkeit geordnet:
Einen Tag über 12 finden. Suche in der Datumsspalte nach einem Wert wie 25/12/2026. Ist die erste Zahl größer als zwölf, steht der Tag vorn. Das dauert zehn Sekunden und ist eindeutig.
Mit einer Buchung abgleichen, an die du dich erinnerst. Alles, was du aus dem Gedächtnis datieren kannst, klärt die Reihenfolge sofort.
Wandle dann ausdrücklich um, statt etwas raten zu lassen:
duckdb -c "SELECT strptime(\"Transaction Date\", '%d/%m/%Y') d, * FROM read_csv('clean.csv', all_varchar=true)"
all_varchar=true ist die wichtigere Hälfte: Der Reader erkennt damit gar keine Typen mehr, und du entscheidest jede Umwandlung selbst. Das schützt auch Referenznummern und Kontoziffern, die sonst als Fließkommazahlen ankämen.
Den Betrag vereinheitlichen
Du willst eine einzige numerische Spalte mit Vorzeichen. Dafür gibt es drei Ausgangsformen.
Getrennte Spalten Debit und Credit. Zusammenführen, Abbuchungen negativ:
COALESCE(-TRY_CAST(replace("Debit", ',', '') AS DOUBLE), TRY_CAST(replace("Credit", ',', '') AS DOUBLE), 0)
Text mit Trennzeichen oder Symbolen. Entferne vor der Umwandlung alles, was keine Ziffer, kein Minus und kein Dezimalpunkt ist. £1,234.56 und 1 234,56 brauchen das beide, und beim zweiten muss zusätzlich das Dezimalkomma behandelt werden.
Buchhalterische Negativwerte. (45.00) bedeutet −45,00. Standardmäßig wandelt das nichts korrekt um. Ersetze zuerst die Klammern.
Prüfe die Umwandlung, bevor du einer Summe traust: Die Zahl der Beträge ungleich NULL muss der Zahl der Buchungszeilen entsprechen. Ein fehlgeschlagenes TRY_CAST liefert dir ein stilles NULL, und ein NULL in einer SUM fehlt einfach. So wird eine Summe plausibel falsch statt offensichtlich kaputt.
Die Beschreibungsspalte aufteilen
In der Beschreibung steckt die nützliche Information, und sie kommt als ein einziger String:
CARD PAYMENT TO TESCO STORES 3421 ON 02-04-2026 GBP 43.19
Einen vollständigen Parser brauchst du selten. Zwei Operationen decken das meiste ab:
Eine Händlerspalte, per Abgleich mit einer Liste von Namen, die dich interessieren. Zwanzig Klauseln wie CASE WHEN description LIKE '%TESCO%' THEN 'Tesco' ordnen den Großteil eines privaten Kontoauszugs zu, und der lange Rest ist die Automatisierung nicht wert.
Eine Spalte für die Buchungsart, aus dem Präfix. CARD PAYMENT, DIRECT DEBIT, FASTER PAYMENT, ATM. Banken sind dabei innerhalb eines Exports konsequent, und die Gruppierung nach Art sagt oft mehr als die nach Händler.
Was du lieber nicht versuchst: einen verlässlichen Betrag oder ein Datum aus der Beschreibung zu ziehen. Beides gibt es schon als Spalte, und die Kopien im Text sind anders formatiert und widersprechen sich manchmal.
Dann die eigentliche Frage stellen
Sobald die Datei ein Datum, einen Betrag mit Vorzeichen und einen Händler hat, braucht jede Frage nur eine Zeile:
SELECT strftime(d, '%Y-%m') month, sum(amount) FROM tx GROUP BY month ORDER BY month
SELECT merchant, count(*) n, sum(amount) FROM tx WHERE amount < 0 GROUP BY merchant ORDER BY sum(amount) LIMIT 20
SELECT * FROM tx WHERE amount < -100 ORDER BY amount
Monatssaldo, größte Ausgaben nach Händler, alles über hundert. Diese drei beantworten das meiste, wofür jemand einen Kontoauszug überhaupt öffnet.
SQL und der visuelle Filter-Editor laufen direkt auf der Datei, dort wo sie liegt. Das ist der Punkt, wenn es ein Bankexport ist, den du lieber nirgends hochlädst. Diagramme kommen aus derselben Abfrage, eine Monatssumme wird also im selben Schritt zum Balkendiagramm.
Was es kannDieser letzte Punkt verdient eine klare Aussage. Ein Kontoauszug gehört zu den sensibelsten Dateien, mit denen die meisten Menschen zu tun haben: jeder Händler, jeder Ort, jede regelmäßige Zahlung und oft eine teilweise Kontonummer. Kostenlose Online-CSV-Viewer und Seiten zum „Kontoauszug umwandeln“ laden alles auf einen Server, über den du nichts weißt. Für genau diese Datei ist ein Tool, das lokal arbeitet, keine Pingeligkeit, sondern die naheliegende Standardwahl.
Für jemand anderen aufbereiten
Oft öffnest du den Kontoauszug, weil jemand einen Teil davon braucht: der Steuerberater, die Vermieterin, eine Spesenabrechnung. Die Arbeit besteht im Weglassen:
- Behalte die Spalten, auf die es ankommt: Datum, Beschreibung, Betrag. Lösche den Rest, auch den laufenden Saldo und die Kontoziffern.
- Filtere auf den Zeitraum oder die Kategorie, die tatsächlich verlangt wird.
- Ergänze eine Kategorie-Spalte, falls danach gefragt wird.
- Exportiere und prüfe, ob die Summe im Export mit der Summe deines Filters übereinstimmt.
Die Saldospalte solltest du bewusst entfernen und nicht aus Bequemlichkeit stehen lassen, denn sie verrät deutlich mehr als die Buchungen selbst.
Spalten löschen, auf einen Zeitraum filtern und eine berechnete Kategorie-Spalte ergänzen sind hier direkte Bearbeitungen. Formelspalten speichern ihre Ergebnisse in der CSV, die Datei, die du weitergibst, ist also eine einfache CSV, die sich bei jedem Empfänger korrekt öffnet.
Was es kannMehrere Monate, mehrere Konten
Banken exportieren jeweils einen Zeitraum, deshalb braucht jede Frage über ein ganzes Jahr mehrere Dateien. Zwei Dinge solltest du vor dem Zusammenführen tun:
Prüfe, ob die Kopfzeilen übereinstimmen. Banken ändern ihre Exportformate von Jahr zu Jahr, und eine Spalte, die ihre Position gewechselt hat, bringt beim blinden Aneinanderhängen alles dahinter durcheinander. Vergleiche zuerst die Kopfzeilen. Die Anleitung zum Zusammenführen von CSV-Dateien beschreibt das Zusammenführen anhand der Spaltennamen, das dagegen gefeit ist.
Ergänze eine Kontospalte, bevor du Dateien verschiedener Konten kombinierst. Ohne sie taucht eine Überweisung zwischen deinen eigenen Konten doppelt auf, einmal als Abgang und einmal als Eingang, und jede Summe, die das ignoriert, liegt um das Doppelte der Überweisung daneben. Die Quelle zu markieren und interne Überweisungen dann ausdrücklich auszuschließen, ist der einzige Weg zu einer Haushaltssumme, die etwas aussagt.