ETL-Skripte mit Claude entwickeln
AI generated
Claude
>_
Claude AI · ETL · Datentransformation · Datenqualität
ETL-Skripte mit Claude entwickeln
robust, idempotent und mit eingebauter Qualitätsprüfung

Ein ETL-Skript, das beim ersten Testlauf funktioniert, aber beim zweiten Lauf doppelte Datensätze erzeugt oder bei einem Teilfehler die Zielquelle in einem inkonsistenten Zustand hinterlässt, ist keine Seltenheit. Claude hilft, diese Fallstricke von Anfang an zu vermeiden, indem es Idempotenz, Fehlerbehandlung und Datenqualitätsprüfungen direkt in die generierte Extraktions-, Transformations- und Ladelogik einbaut. Dieser Artikel zeigt den kompletten Entwicklungsprozess an einem realistischen Migrationsbeispiel.

17 Min. Lesezeit Idempotenz · Fehlertoleranz · Datenqualität Python · SQL · Claude Code

1. Warum ETL-Skripte selten beim ersten Wurf robust sind

Ein typisches ETL-Skript entsteht oft unter Zeitdruck: Daten müssen von System A nach System B, die Logik wird schnell geschrieben, ein Testlauf mit einer Handvoll Zeilen funktioniert, das Skript geht in Produktion. Die eigentlichen Probleme zeigen sich erst später, wenn das Skript ein zweites Mal läuft und Duplikate erzeugt, wenn ein Netzwerkfehler mitten im Lauf die Zieltabelle in einem inkonsistenten Zustand zurücklässt, oder wenn ein unerwarteter NULL-Wert die gesamte Transformation zum Absturz bringt.

Claude kann diese Klasse von Problemen deutlich reduzieren, wenn man es nicht nur bittet, "Daten von A nach B zu bringen", sondern explizit nach Idempotenz, Fehlerbehandlung und Wiederanlauffähigkeit fragt. Der Unterschied zwischen einem naiven und einem robusten ETL-Skript liegt selten in der Kernlogik der Transformation, sondern in der Behandlung der Randfälle: Was passiert bei einem doppelten Lauf, was passiert bei einem Teilfehler, was passiert bei unerwarteten Datenformaten. Dieser Artikel zeigt, wie man diese Aspekte systematisch in den Prompt einbringt, statt sie nach einem Produktionsvorfall nachträglich zu reparieren.

2. Extraktion generieren lassen: Quellsysteme richtig beschreiben

Der Extraktionsschritt eines ETL-Skripts muss mit den Eigenheiten der Quelle umgehen können: Paginierung bei APIs, Rate-Limits, inkrementelle versus vollständige Extraktion. Claude generiert brauchbaren Extraktionscode, wenn man die Quelle konkret beschreibt, inklusive Antwortformat, Paginierungsmechanismus und bekannter Limits. Ohne diese Details neigt Claude dazu, eine naive Version zu schreiben, die bei der ersten Seite mit mehr als tausend Datensätzen abbricht oder das Rate-Limit der Quelle ignoriert.

Besonders wichtig bei wiederkehrenden ETL-Jobs ist die inkrementelle Extraktion: Statt bei jedem Lauf die komplette Quelle zu lesen, sollte nur der seit dem letzten Lauf veränderte Datenbestand abgefragt werden. Claude generiert diese Logik zuverlässig, wenn man ein Feld für den letzten erfolgreichen Extraktionszeitpunkt vorgibt und explizit nach einer inkrementellen Strategie fragt, statt implizit eine volle Extraktion zu erwarten.


# ETL extraction step, generated with explicit pagination and rate limit context
import time
import requests
from datetime import datetime, timezone

def extract_orders_incremental(since: datetime, api_key: str) -> list[dict]:
    """
    Extracts orders modified since the given timestamp.

    @param since Timestamp of the last successful extraction run.
    @param api_key Authentication token for the source API.
    @return List of order records as returned by the source system.
    """
    orders: list[dict] = []
    page = 1
    while True:
        response = requests.get(
            "https://source-system.example/api/orders",
            params={"modified_since": since.isoformat(), "page": page, "per_page": 200},
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=30,
        )
        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", "5"))
            time.sleep(retry_after)
            continue
        response.raise_for_status()

        payload = response.json()
        orders.extend(payload["data"])
        if not payload.get("has_more"):
            break
        page += 1

    return orders

# Store the timestamp only after the full pipeline (extract+transform+load)
# succeeds, never right after extraction — a partial failure downstream
# must not advance the incremental watermark.

3. Idempotenz von Anfang an mitdenken

Idempotenz bedeutet, dass ein wiederholter Lauf desselben ETL-Skripts mit denselben Eingabedaten zum selben Endzustand führt, statt Duplikate zu erzeugen. Das ist die wichtigste Eigenschaft, die ein produktionstaugliches ETL-Skript braucht, weil Wiederholungen nach einem Fehler, einem Timeout oder einer manuellen Neuauslösung in der Praxis unvermeidlich sind. Ohne Idempotenz führt jeder erneute Lauf potenziell zu doppelten Zeilen im Ziel, was besonders bei Finanzdaten oder Bestandsdaten gravierende Folgen hat.

Claude setzt Idempotenz zuverlässig um, wenn man es explizit im Prompt einfordert, typischerweise über UPSERT-Operationen (INSERT ... ON DUPLICATE KEY UPDATE oder ON CONFLICT) statt reiner INSERT-Statements, oder über einen eindeutigen Business-Key, der vor dem Einfügen geprüft wird. Ohne diese explizite Anforderung generiert Claude in kurzen Beispiel-Snippets manchmal einfache INSERT-Logik, die bei einem zweiten Lauf Duplikate erzeugt.


-- WRONG: plain INSERT, creates duplicates on every re-run
-- INSERT INTO target_orders (order_ref, customer_id, total)
-- VALUES ('ORD-2026-0512', 4471, 89.90);

-- RIGHT: idempotent UPSERT using the natural business key
INSERT INTO target_orders (order_ref, customer_id, total, updated_at)
VALUES ('ORD-2026-0512', 4471, 89.90, NOW())
ON DUPLICATE KEY UPDATE
  customer_id = VALUES(customer_id),
  total = VALUES(total),
  updated_at = VALUES(updated_at);
-- Requires a UNIQUE constraint on order_ref, established by the schema

-- For PostgreSQL targets, Claude generates the equivalent:
-- INSERT INTO target_orders (order_ref, customer_id, total, updated_at)
-- VALUES ('ORD-2026-0512', 4471, 89.90, NOW())
-- ON CONFLICT (order_ref) DO UPDATE SET
--   customer_id = EXCLUDED.customer_id,
--   total = EXCLUDED.total,
--   updated_at = EXCLUDED.updated_at;

4. Transformationslogik mit klaren Geschäftsregeln generieren

Die Transformationslogik eines ETL-Skripts ist der Ort, an dem fachliche Regeln umgesetzt werden: Preisberechnungen, Statusabbildungen zwischen zwei Systemen mit unterschiedlichen Enum-Werten, oder das Zusammenführen mehrerer Quellfelder in ein Zielformat. Claude generiert diese Logik am zuverlässigsten, wenn die Geschäftsregel als konkrete Beispieltabelle vorliegt, etwa "Status A wird zu Status X, Status B und C werden beide zu Status Y", statt als abstrakte Beschreibung.

Ein häufiger Fehler bei manuell geschriebenen Transformationen ist das Vergessen von Randfällen: Was passiert, wenn ein Quellstatus auftritt, der in keiner der bekannten Mapping-Regeln vorkommt? Claude generiert auf Nachfrage explizite else-Zweige, die einen unbekannten Wert klar protokollieren und in eine definierte Fallback-Kategorie einordnen, statt ihn stillschweigend zu verwerfen oder das Skript abstürzen zu lassen.

5. Fehlertoleranz: Teilfehler ohne Totalausfall behandeln

Bei der Verarbeitung tausender Datensätze führt ein einzelner fehlerhafter Datensatz, etwa ein unerwartetes Datumsformat oder ein fehlendes Pflichtfeld, in einer naiven Implementierung oft zum Abbruch der gesamten Verarbeitung. Ein robustes ETL-Skript fängt solche Einzelfehler ab, protokolliert den problematischen Datensatz mit ausreichend Kontext für eine spätere Analyse, und setzt die Verarbeitung der restlichen Datensätze fort. Claude generiert dieses Muster zuverlässig, wenn man explizit nach "graceful degradation pro Zeile statt Totalausfall" fragt.

Wichtig ist dabei die Balance: Nicht jeder Fehler sollte stillschweigend übersprungen werden. Ein fehlendes optionales Feld ist unkritisch, ein fehlender Primärschlüssel oder eine offensichtlich korrupte Zeile sollte den gesamten Lauf stoppen, weil sie auf ein strukturelles Problem in der Quelle hindeutet, das eine einzelne Fehlerbehandlung nicht lösen kann. Diese Unterscheidung sollte man Claude explizit mitgeben, damit die generierte Fehlerbehandlung weder zu nachsichtig noch zu strikt ausfällt.


# Row-level error tolerance: continue processing, log failures with context
from dataclasses import dataclass, field

@dataclass
class TransformResult:
    """Aggregates successful and failed rows from a transformation pass."""
    succeeded: list[dict] = field(default_factory=list)
    failed: list[dict] = field(default_factory=list)

def transform_batch(raw_records: list[dict]) -> TransformResult:
    """Transforms each record independently, isolating per-row failures."""
    result = TransformResult()
    for record in raw_records:
        try:
            transformed = {
                "order_ref": record["order_ref"],          # required, hard fail if missing
                "customer_id": int(record["customer_id"]),  # required
                "total": round(float(record.get("total", 0)), 2),  # optional, default 0
                "notes": record.get("notes"),                # optional, may be None
            }
            result.succeeded.append(transformed)
        except (KeyError, ValueError, TypeError) as exc:
            result.failed.append({"record": record, "error": str(exc)})
            logger.warning(f"Skipping malformed record: {exc}", extra={"record": record})

    if len(result.failed) > len(raw_records) * 0.1:
        # More than 10% failures indicates a structural source problem —
        # stop the whole run instead of silently accepting bad data quality
        raise RuntimeError(f"{len(result.failed)} of {len(raw_records)} records failed, aborting run")

    return result

6. Datenqualitätsprüfungen direkt in die Pipeline einbauen

Statt Datenqualität nachträglich per separatem Prüfskript zu kontrollieren, lohnt es sich, Qualitätsprüfungen direkt in das ETL-Skript zu integrieren. Claude generiert solche Prüfungen typischerweise als eigenständigen Schritt zwischen Transformation und Ladevorgang: Stimmt die Zeilenzahl mit der Erwartung überein, liegen numerische Werte in einem plausiblen Bereich, sind Pflichtfelder tatsächlich immer gefüllt. Schlägt eine dieser Prüfungen fehl, wird der Ladevorgang blockiert, statt fragwürdige Daten stillschweigend zu übernehmen.

Diese eingebauten Prüfungen sind besonders wertvoll bei wiederkehrenden Migrationen, weil sie Regressionen sofort sichtbar machen. Ändert sich beispielsweise unbemerkt das Antwortformat der Quell-API, bricht die Prüfung mit einer klaren Meldung ab, statt fehlerhafte oder unvollständige Daten in das Zielsystem zu schreiben. Der Aufwand für diese Prüfungen ist mit Claude gering, weil die Regeln aus der ohnehin vorhandenen Transformationslogik meist direkt ableitbar sind.

7. Einmalige Datenmigrationen versus wiederkehrende ETL-Jobs

Eine einmalige Datenmigration, etwa der Umzug eines Legacy-Shops in ein neues System, unterscheidet sich in wichtigen Punkten von einem wiederkehrenden ETL-Job. Bei einer einmaligen Migration ist Idempotenz zwar weiterhin sinnvoll für Testläufe, aber es gibt keinen Bedarf für inkrementelle Extraktion, dafür einen höheren Bedarf an ausführlicher Validierung vor dem finalen Cutover. Claude sollte im Prompt explizit wissen, um welche Art von Aufgabe es sich handelt, weil sich die generierte Struktur deutlich unterscheidet.

Bei einmaligen Migrationen empfiehlt sich zusätzlich ein Trockenlauf-Modus, bei dem alle Transformationen ausgeführt, aber keine Schreiboperationen an das Zielsystem gesendet werden. Claude kann diesen Modus als Flag in das generierte Skript einbauen, sodass ein vollständiger Testlauf mit echten Produktionsdaten möglich ist, ohne das Risiko, das Zielsystem versehentlich zu verändern, bevor der eigentliche Cutover ansteht.

8. ETL-Skripte gegen Testdaten verifizieren, bevor sie produktiv laufen

Jedes von Claude generierte ETL-Skript sollte vor dem produktiven Einsatz gegen eine repräsentative Stichprobe echter Daten getestet werden, inklusive bekannter Randfälle wie NULL-Werten, doppelten Schlüsseln und ungewöhnlichen Zeichen. Ein bewährtes Vorgehen: Claude bitten, zusätzlich zum eigentlichen ETL-Code auch Testfälle mit genau diesen Randfällen zu generieren, sodass die Fehlerbehandlung nicht nur behauptet, sondern nachweislich funktioniert.

Bei Migrationen mit hohem Risiko lohnt sich ein zweistufiges Vorgehen: Erst gegen eine anonymisierte Kopie der Produktionsdaten testen, dann einen begrenzten Teil der echten Daten migrieren und stichprobenartig gegen die Quelle validieren, bevor der vollständige Lauf gestartet wird. Diese Vorsicht kostet Zeit, verhindert aber die deutlich teureren Folgen einer fehlerhaften vollständigen Migration.

9. ETL-Ansätze im direkten Vergleich

Je nach Anforderung unterscheidet sich, welche Eigenschaften ein von Claude generiertes ETL-Skript zwingend haben sollte. Die folgende Übersicht ordnet typische Szenarien ein.

Szenario Naive Generierung Mit expliziten Anforderungen Kritische Eigenschaft
Wiederkehrender ETL-Job Duplikate bei Re-Run UPSERT, inkrementell Idempotenz
Einmalige Migration Volllauf ohne Trockenlauf Dry-Run-Modus, Validierung vor Cutover Sicherheit vor Cutover
Große Datenmengen Abbruch bei einem Fehler Row-Level-Fehlertoleranz Fehlertoleranz
Kritische Finanzdaten Stille Datenqualitätsfehler Eingebaute Qualitätsprüfung Datenqualität
Externe API als Quelle Ignoriert Rate-Limits Retry mit Backoff, Paginierung Robustheit gegen Quelle

In jedem dieser Szenarien liegt der Unterschied nicht in der Fähigkeit von Claude, den Kerncode zu schreiben, sondern darin, ob die kritische Eigenschaft explizit im Prompt gefordert wurde. Wer diese Anforderungen als feste Checkliste vor jeder ETL-Generierung durchgeht, reduziert die Zahl der Produktionsvorfälle erheblich.

Mironsoft

Datenmigrationen, ETL-Entwicklung und KI-gestützte Automatisierung

Datenmigration ohne böse Überraschungen?

Wir entwickeln robuste, idempotente ETL-Skripte mit eingebauten Qualitätsprüfungen und Fehlertoleranz, testen sie gegen reale Datenstichproben und begleiten den kompletten Cutover von der Extraktion bis zur Validierung im Zielsystem.

Idempotente Pipelines

UPSERT-basierte ETL-Skripte, die bei Wiederholung keine Duplikate erzeugen

Datenmigration

Legacy-System-Umzüge mit Dry-Run und schrittweiser Validierung

Qualitätsprüfungen

Automatisierte Checks direkt in der Transformationslogik

10. Zusammenfassung

ETL-Skripte mit Claude entwickeln funktioniert am zuverlässigsten, wenn kritische Eigenschaften wie Idempotenz, Fehlertoleranz und Datenqualitätsprüfung von Anfang an explizit eingefordert werden, statt implizit erwartet zu werden. UPSERT-Operationen statt reiner INSERTs verhindern Duplikate bei Wiederholungsläufen, row-level Fehlerbehandlung verhindert, dass ein einzelner fehlerhafter Datensatz die gesamte Verarbeitung stoppt, und eingebaute Qualitätsprüfungen machen Regressionen sofort sichtbar statt sie stillschweigend zu übernehmen.

Der Unterschied zwischen einmaligen Datenmigrationen und wiederkehrenden ETL-Jobs sollte im Prompt klar benannt werden, weil sich Anforderungen wie inkrementelle Extraktion oder Dry-Run-Modus grundlegend unterscheiden. Vor jedem produktiven Einsatz bleibt das Testen gegen reale Datenstichproben mit bekannten Randfällen der wichtigste Schritt, um Vertrauen in die generierte Pipeline aufzubauen.

ETL-Skripte mit Claude entwickeln — Das Wichtigste auf einen Blick

Idempotenz einfordern

UPSERT statt INSERT explizit im Prompt verlangen, um Duplikate bei Wiederholungsläufen zu vermeiden.

Row-Level-Fehlertoleranz

Einzelne fehlerhafte Datensätze isoliert behandeln, damit ein Fehler nicht den gesamten Lauf stoppt.

Qualität in die Pipeline

Prüfungen direkt zwischen Transformation und Ladevorgang einbauen, statt sie nachträglich separat auszuführen.

Migration versus Job unterscheiden

Einmalige Migrationen brauchen Dry-Run und Cutover-Validierung, wiederkehrende Jobs brauchen inkrementelle Extraktion.

11. FAQ: ETL-Skripte mit Claude entwickeln

1Warum sind generierte ETL-Skripte oft nicht idempotent?
Idempotenz muss explizit im Prompt gefordert werden, sonst entsteht oft einfache INSERT-Logik.
2Migration versus wiederkehrender Job, was ist der Unterschied?
Migration braucht Dry-Run und Cutover-Validierung, wiederkehrende Jobs brauchen inkrementelle Extraktion.
3Wie behandelt man einzelne fehlerhafte Datensätze?
Row-Level-Fehlerbehandlung: isoliert protokollieren und überspringen, bei zu hoher Fehlerquote abbrechen.
4Wie baut man Datenqualitätsprüfungen ein?
Als eigenständigen Schritt zwischen Transformation und Laden, der bei Fehlschlag den Ladevorgang blockiert.
5Kann Claude inkrementelle Extraktion generieren?
Ja, mit einem Feld für den letzten Extraktionszeitpunkt und expliziter Anfrage nach inkrementeller Strategie.
6Was ist ein Dry-Run-Modus?
Ein Modus ohne Schreiboperationen am Zielsystem, für risikofreien Testlauf mit echten Produktionsdaten.
7Wie testet man ein generiertes ETL-Skript?
Gegen reale Datenstichproben mit bekannten Randfällen, Claude kann passende Testfälle mitgenerieren.
8Wie geht das Skript mit Rate-Limits um?
Mit Retry-Logik auf Basis von Statuscode und Retry-After-Header, wenn im Prompt explizit gefordert.
9Was passiert bei unbekannten Statuswerten?
Ein expliziter Fallback-Zweig protokolliert und kategorisiert unbekannte Werte statt sie zu verwerfen.
10Wie hoch sollte die Fehlertoleranz-Schwelle sein?
Üblich ist ein Abbruch ab etwa zehn Prozent Fehlerquote, als Hinweis auf ein strukturelles Quellproblem.