PublicData – kostenlose CSV-Datensätze für DACH und international

PublicData ist meine offene Sammlung von Referenzdatensätzen als CSV-Dateien: Postleitzahlen, Gemeinden, Landkreise, Vorwahlen, Kfz-Kennzeichen und Einwohnerzahlen für Deutschland, Österreich und die Schweiz, dazu internationale Stammdaten wie Länder-, Währungs- und Sprachcodes.

Alle Dateien liegen in meinem öffentlichen Repository und sind kostenfrei, ohne Anmeldung und ohne API-Key abrufbar:

code.beautifulmachines.dev/jakoubek/publicdata

Warum diese Sammlung?

Fast jedes Datenprojekt braucht irgendwann dieselben Stammdaten. Eine Kundenliste soll nach Bundesland ausgewertet werden, Adressen sollen gegen gültige Postleitzahlen geprüft werden, ein Report soll Umsätze pro Landkreis zeigen.

Die Daten sind amtlich und frei verfügbar, aber sie liegen bei Destatis, der Statistik Austria, dem BFS oder der Bundesnetzagentur in Formaten, die für die direkte Weiterverarbeitung ungeeignet sind: Excel-Dateien mit Kopfzeilen über mehrere Ebenen, Fußnoten mitten in den Daten, wechselnde Spaltennamen, mal Semikolon, mal Tabulator, mal Windows-1252.

Diese Aufbereitung habe ich für meine eigenen Projekte ohnehin gemacht. Statt sie in jedem Projekt zu wiederholen, liegt sie jetzt öffentlich, in einem einheitlichen Format vor:

  • UTF-8 kodiert
  • Komma als Trennzeichen
  • LF als Zeilenende
  • Eine Kopfzeile mit stabilen, sprechenden Spaltennamen
  • Führende Nullen erhalten (08 bleibt 08 und wird nicht zu 8)
  • Über gemeinsame Schlüssel wie den Amtlichen Gemeindeschlüssel verknüpfbar

Die Datensätze

International

Datei Inhalt Zeilen
countries.csv Länder mit ISO-3166-1-Codes (alpha-2, alpha-3, numerisch), Region und Subregion 249
currencies.csv Währungen nach ISO 4217 mit Code, Name und Dezimalstellen 178
languages.csv Sprachen nach ISO 639 486
calling_codes.csv Internationale Telefonvorwahlen, verknüpft mit dem Ländercode 248

Deutschland

Datei Inhalt Zeilen
bundeslaender_de.csv Bundesländer mit AGS- und ISO-Code 16
landkreise_de.csv Landkreise und kreisfreie Städte 400
gemeinden_de.csv Gemeinden, verknüpft mit Landkreis und Bundesland 10.943
postleitzahlen_de.csv Postleitzahlen mit Ort, Bundesland und AGS 8.293
vorwahlen_de.csv Telefonvorwahlen mit Ort 5.200
kfz_kennzeichen_de.csv Kfz-Unterscheidungszeichen 769
einwohner_de.csv Bevölkerung, Fläche und Dichte je Gemeinde (Stand 31.12.2024) 10.943

Österreich

Datei Inhalt Zeilen
bundeslaender_at.csv Bundesländer mit ÖSTAT- und ISO-Code 9
gemeinden_at.csv Gemeinden mit Gemeindekennziffer 2.092
postleitzahlen_at.csv Postleitzahlen mit Ort und Bundesland 2.501
vorwahlen_at.csv Telefonvorwahlen mit Ort 1.022
einwohner_at.csv Bevölkerung je Gemeinde (Stand 1.1.2026) 2.092

Schweiz

Datei Inhalt Zeilen
kantone_ch.csv Kantone mit Abkürzung und ISO-Code 26
gemeinden_ch.csv Gemeinden mit BFS-Nummer, Bezirk und Kanton 2.131
postleitzahlen_ch.csv Postleitzahlen mit Ort und Kanton 3.362
vorwahlen_ch.csv Geografische Vorwahlgebiete 20
einwohner_ch.csv Ständige Wohnbevölkerung je Gemeinde (Stand 31.12.2024) 2.131

Direkt einlesen mit DuckDB

DuckDB ist eine analytische Datenbank, die vollständig im eigenen, lokalen Prozess läuft: kein Server und keine Installation im klassischen Sinn. Für genau solche Aufgaben ist sie ideal: CSV-Dateien lesen, verknüpfen, auswerten und exportieren.

Dabei liest DuckDB CSV-Dateien direkt über HTTPS. Sie müssen nichts herunterladen.

SELECT * FROM read_csv(
    'https://code.beautifulmachines.dev/jakoubek/publicdata/raw/branch/main/bundeslaender_de.csv',
    header = true,
    all_varchar = true
);

Der Parameter all_varchar = true ist wichtig. Er verhindert, dass DuckDB Schlüsselfelder als Zahlen interpretiert und dabei führende Nullen wegwirft. Aus dem AGS-Code 08 für Baden-Württemberg würde sonst eine 8, und der Join gegen Ihre eigenen Daten liefert keinen Treffer mehr.

Basis-URL einmal setzen

Damit die folgenden Beispiele lesbar bleiben, lege ich die Basis-URL als Variable ab:

SET VARIABLE base =
    'https://code.beautifulmachines.dev/jakoubek/publicdata/raw/branch/main/';

Als Tabelle übernehmen

Wenn Sie mehrfach mit den Daten arbeiten, laden Sie sie einmal in eine persistente Tabelle:

CREATE TABLE postleitzahlen AS
SELECT * FROM read_csv(
    getvariable('base') || 'postleitzahlen_de.csv',
    header = true,
    all_varchar = true
);

Die Datei enthält die Spalten plz, ort, bundesland und ags_code.

Mehrere Datensätze verknüpfen

Die deutschen Datensätze sind über den Amtlichen Gemeindeschlüssel hierarchisch verbunden: Gemeinde, Landkreis, Bundesland.

SELECT
    b.name   AS bundesland,
    count(*) AS anzahl_gemeinden
FROM read_csv(getvariable('base') || 'gemeinden_de.csv',
              header = true, all_varchar = true) g
JOIN read_csv(getvariable('base') || 'landkreise_de.csv',
              header = true, all_varchar = true) l
    ON g.kreis_code = l.ags_code
JOIN read_csv(getvariable('base') || 'bundeslaender_de.csv',
              header = true, all_varchar = true) b
    ON l.state_code = b.ags_code
GROUP BY b.name
ORDER BY anzahl_gemeinden DESC;

Die Einwohnerdaten hängen ebenfalls am AGS-Code, hier auf Gemeindeebene. So kommen Sie in einer Abfrage zu den zehn größten Städten Deutschlands:

SELECT
    g.name,
    g.bundesland,
    e.population::bigint AS einwohner
FROM read_csv(getvariable('base') || 'einwohner_de.csv',
              header = true, all_varchar = true) e
JOIN read_csv(getvariable('base') || 'gemeinden_de.csv',
              header = true, all_varchar = true) g
    ON e.ags_code = g.ags_code
ORDER BY einwohner DESC
LIMIT 10;

Ihre eigenen Daten anreichern

Der häufigste Anwendungsfall: eine eigene Datei mit Kundenadressen um die Region ergänzen.

SELECT
    k.kundennummer,
    k.plz,
    p.ort,
    p.bundesland
FROM read_csv('kunden.csv', header = true, all_varchar = true) k
LEFT JOIN postleitzahlen p ON k.plz = p.plz;

Zeilen ohne Treffer zeigen sofort, wo Ihre Stammdaten fehlerhaft sind: Tippfehler in Postleitzahlen, veraltete Orte, vertauschte Felder.

Ergebnisse exportieren

DuckDB schreibt in nahezu jedes Format:

COPY (SELECT * FROM postleitzahlen)
    TO 'postleitzahlen.parquet' (FORMAT parquet);

COPY (SELECT * FROM postleitzahlen)
    TO 'postleitzahlen.json' (FORMAT json, ARRAY true);

Direkt in Ihre Datenbank

Mit der Postgres-Erweiterung schreiben Sie die Daten in einem Schritt in Ihre bestehende PostgreSQL-Datenbank. Sie benötigen dafür keine zusätzliche Zwischendatei und kein Import-Skript:

INSTALL postgres;
LOAD postgres;

ATTACH 'dbname=meinedb user=app host=localhost' AS pg (TYPE postgres);

CREATE TABLE pg.postleitzahlen AS
SELECT * FROM read_csv(
    'https://code.beautifulmachines.dev/jakoubek/publicdata/raw/branch/main/postleitzahlen_de.csv',
    header = true,
    all_varchar = true
);

Ohne SQL-Datei, direkt in der Shell

duckdb -c "SELECT * FROM read_csv('https://code.beautifulmachines.dev/jakoubek/publicdata/raw/branch/main/kantone_ch.csv', header = true, all_varchar = true)"

Mit Python

Auch ohne DuckDB genügt eine Zeile:

import pandas as pd

url = "https://code.beautifulmachines.dev/jakoubek/publicdata/raw/branch/main/countries.csv"
countries = pd.read_csv(url, dtype=str)

dtype=str erfüllt hier denselben Zweck wie all_varchar in DuckDB.

Nutzen für Unternehmen

Typische Situationen aus meinen Projekten:

Auswertungen bekommen eine geografische Dimension. Umsatz pro Postleitzahl ergibt eine Liste mit 8.293 Zeilen. Für die Auswertung nach Bundesland oder Landkreis fehlt nur die Zuordnungstabelle.

Datenqualität wird prüfbar. Ein Join gegen die Postleitzahlen-Liste macht in Sekunden sichtbar, welche Adressen in Ihrem CRM- oder ERP-System fehlerhaft sind.

Auswahllisten und Formulare werden konsistent. Länder- und Währungscodes nach ISO-Norm statt frei getippter Werte zahlen sich spätestens bei der ersten Schnittstelle zu einem anderen System aus.

Gebietszuschnitt und Tourenplanung bekommen eine Grundlage. Vertriebsgebiete, Zustellbezirke, Servicegebiete: Jede Gebietslogik beginnt mit der Zuordnung von Postleitzahl zu Gemeinde und Landkreis.

Kennzahlen werden vergleichbar. Absolute Zahlen pro Region sagen wenig, solange die Regionen unterschiedlich groß sind. Mit der Einwohnerzahl als Bezugsgröße rechnen Sie Verkaufszahlen pro Kopf und stellen Regionen sinnvoll nebeneinander.

Stammdaten müssen nicht selbst gepflegt werden. Gemeinden fusionieren, Postleitzahlen kommen hinzu, Einwohnerzahlen werden fortgeschrieben. Wenn die Daten über eine URL kommen, ist die Aktualisierung ein erneuter Aufruf und kein Ticket.

Ein Data-Warehouse ist dafür nicht nötig. DuckDB läuft auf einem Notebook, in einem Container oder in einem Cron-Job. Für Datenmengen dieser Größenordnung braucht es keine eigene Server-Infrastruktur.

Lizenz und Quellen

Die Datensätze stehen unter der Creative-Commons-Lizenz Attribution 4.0 International (CC BY 4.0). Sie dürfen sie kopieren, weitergeben, verändern und auch kommerziell nutzen, in internen Auswertungen ebenso wie in einem Produkt, das Sie verkaufen. Eine Rückfrage bei mir ist nicht nötig, eine Lizenzgebühr fällt nicht an.

Die einzige Bedingung ist die Namensnennung.

So geben Sie die Quelle an

Ein Satz genügt, etwa im Quellenverzeichnis eines Reports, auf einer Impressumsseite oder als Kommentar im Code:

Datenbasis: PublicData von Oliver Jakoubek, lizenziert unter CC BY 4.0, https://www.jakoubek.net/publicdata/

Zum Kopieren für Ihre Dokumentation oder Ihre Website:

Datenbasis: [PublicData](https://www.jakoubek.net/publicdata/) von Oliver Jakoubek, lizenziert unter [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.de).

In einer Anwendung reicht die Nennung an der Stelle, an der Sie ohnehin Ihre Drittanbieter-Lizenzen aufführen. In einem Diagramm genügt eine Quellenzeile unter der Grafik.

Die zugrunde liegenden Daten stammen aus amtlichen und offenen Quellen, unter anderem von Destatis, der Statistik Austria, dem Bundesamt für Statistik (BFS), der Bundesnetzagentur und GeoNames. Reine Fakten wie Postleitzahlen, Gemeindenamen und Einwohnerzahlen sind für sich genommen nicht urheberrechtlich geschützt. Die Lizenz bezieht sich auf meine Aufbereitung und Zusammenstellung.

Alle Angaben ohne Gewähr. Verbindlich ist immer die jeweilige amtliche Originalquelle.

Fehler gefunden? Datensatz vermisst?

Das Repository ist öffentlich. Wenn Ihnen ein Fehler auffällt oder ein Datensatz fehlt, der hier gut hineinpassen würde, dann schreiben Sie mir. Ich pflege die Sammlung fortlaufend weiter.

Sie brauchen mehr als die Rohdaten?

Die CSV-Dateien sind der einfache Teil. Aufwendig wird es meist danach: Die Daten sollen regelmäßig aktualisiert in Ihre Datenbank fließen, mit Ihren eigenen Stammdaten abgeglichen werden, Dubletten sollen erkannt, Adressen normalisiert und Auswertungen automatisiert erstellt werden.

Genau das mache ich beruflich, seit über 20 Jahren: Datenintegration, Datenbankentwicklung und Automatisierung. Wenn Sie öffentliche Daten in Ihren Systemen nutzbar machen wollen und nicht wissen, wo Sie anfangen sollen, dann sprechen Sie mich an.