Claude Code & dbt: Data-Transformationen schneller entwickeln

dbt (data build tool) hat sich als Standard für die Transformationsschicht im modernen Data Stack durchgesetzt. Wer mit einem Data Warehouse wie BigQuery, Snowflake oder DuckDB arbeitet, kennt das Muster: Rohdaten landen per ELT im Warehouse, und dbt übernimmt die Transformation — sauber, versioniert, testbar. Was fehlt, ist oft Zeit: Models tippen, schema.yml pflegen, Macros schreiben, ref()-Ketten debuggen. Genau hier setzt Claude Code dbt an.

Dieser Artikel erklärt zuerst die dbt-Grundlagen für alle, die noch nicht täglich damit arbeiten — und zeigt dann konkret, wie Claude Code die Entwicklung beschleunigt.

Claude Code Mastery — auch für Data Engineering

dbt ist ein Anwendungsfall unter vielen. Im Kurs lernst du Claude Code systematisch einzusetzen: Agents, Hooks, MCP-Server, Multi-Agent-Workflows — vollständig auf Deutsch, einmalig bezahlt.

Zum Kurs — Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht

1. Was ist dbt — und warum ELT statt ETL?

Klassisches ETL transformiert Daten bevor sie ins Warehouse kommen. ELT dreht das um: erst laden (Extract + Load), dann transformieren — direkt im Warehouse, mit dessen Rechenleistung. dbt ist das Werkzeug für den letzten Schritt: es nimmt SQL-Dateien, führt sie in der richtigen Reihenfolge aus und hält dabei den Status, die Tests und die Dokumentation aktuell.

Das Besondere: dbt ist kein ETL-Tool im traditionellen Sinne. Es schreibt keine Daten ins Warehouse — es transformiert Daten, die bereits dort sind. Deine Rohtabellen bleiben unberührt; dbt legt neue Tabellen oder Views darüber, sauber getrennt von der Quelle.

Voraussetzungen: dbt benötigt ein Data Warehouse (BigQuery, Snowflake, Redshift, DuckDB u.a.), Python und ein dbt-Profil mit Zugangsdaten. dbt Core ist Open Source; dbt Cloud ist die gehostete Variante. Für lokale Entwicklung reicht dbt Core mit DuckDB vollständig.

2. Models: das Herzstück von dbt

Ein dbt Model ist nichts anderes als eine SQL-Datei mit einem SELECT-Statement. Keine INSERT-, UPDATE- oder CREATE TABLE-Befehle — nur SELECT. dbt erledigt den Rest: es entscheidet anhand der Materialization-Einstellung, ob daraus eine View, eine Tabelle oder ein inkrementelles Update wird.

-- models/marts/fct_orders.sql
SELECT
    o.order_id,
    o.customer_id,
    o.created_at,
    c.country,
    SUM(oi.quantity * oi.unit_price) AS revenue
FROM {{ ref('stg_orders') }} o
JOIN {{ ref('stg_customers') }} c ON o.customer_id = c.customer_id
JOIN {{ ref('stg_order_items') }} oi ON o.order_id = oi.order_id
GROUP BY 1, 2, 3, 4

Das {{ ref('stg_orders') }} ist der Schlüssel: dbt weiß dadurch, dass dieses Model von stg_orders abhängt, und baut den DAG (Directed Acyclic Graph) automatisch. Kein manuelles Ordnen der Ausführungsreihenfolge — dbt leitet sie aus den Abhängigkeiten ab.

Materializations: view, table, incremental, ephemeral

dbt kennt vier Materializations, die du pro Model — oder global im Projekt — festlegen kannst:

3. ref() und source() — Abhängigkeiten explizit machen

ref() referenziert andere dbt Models. source() referenziert Rohdaten-Tabellen, die außerhalb von dbt landen — also die Quelltabellen deines Loaders (Fivetran, Airbyte, Stitch etc.).

-- source() für Rohdaten (aus schema.yml definiert)
SELECT * FROM {{ source('salesforce', 'accounts') }}

-- ref() für andere dbt Models
SELECT * FROM {{ ref('stg_salesforce_accounts') }}

Beide Funktionen machen dbt-Projekte portierbar: Wechselst du das Warehouse oder das Schema, reicht eine Änderung im Profil — keine hartcodierten Tabellennamen im SQL. dbt berechnet außerdem einen Lineage-Graph, der zeigt, welches Model von welchem abhängt. dbt docs generate && dbt docs serve öffnet diesen Graph im Browser.

4. dbt run, build, test — die wichtigsten Befehle

5. Tests, Dokumentation und weitere Features

Schema Tests

dbt bringt vier eingebaute Tests mit, die du in schema.yml deklarierst — ohne SQL schreiben zu müssen:

# models/staging/schema.yml
models:
  - name: stg_orders
    columns:
      - name: order_id
        tests:
          - unique
          - not_null
      - name: status
        tests:
          - accepted_values:
              values: ['placed', 'shipped', 'delivered', 'cancelled']
      - name: customer_id
        tests:
          - relationships:
              to: ref('stg_customers')
              field: customer_id

unique und not_null sind die häufigsten Tests. accepted_values prüft auf erlaubte Werte. relationships ist ein referenzieller Integritätstest. Zusätzlich gibt es singular tests: eigene SQL-Dateien im tests/-Ordner, die bei einem nicht-leeren Ergebnis fehlschlagen.

Jinja, Macros, Seeds und Snapshots

dbt verwendet Jinja2 als Template-Sprache. Das erlaubt Schleifen, Bedingungen und wiederverwendbare Macros — vergleichbar mit Funktionen in einer Programmiersprache:

-- macros/cents_to_euros.sql
{% macro cents_to_euros(column_name) %}
    ({{ column_name }} / 100.0)::NUMERIC(10,2)
{% endmacro %}

-- Verwendung im Model
SELECT {{ cents_to_euros('amount_cents') }} AS amount_euros

Seeds sind CSV-Dateien, die dbt ins Warehouse lädt — nützlich für kleine Referenztabellen wie Länder-Codes oder Produkt-Kategorien. Snapshots implementieren Slowly Changing Dimensions (SCD Typ 2): dbt speichert historische Zustände einer Tabelle, indem es bei jeder Ausführung prüft, welche Zeilen sich geändert haben.

6. Claude Code dbt: konkrete Tipps

Hier liegt der eigentliche Mehrwert von Claude Code dbt: nicht das Ersetzen von SQL-Wissen, sondern das Beschleunigen aller repetitiven Teile.

Models aus Quelltabellen generieren

Der häufigste Startpunkt: du hast eine Rohtabelle und willst ein Staging-Model. Claude Code liest die Tabellenstruktur und generiert das Model — inklusive sinnvoller Umbenennung, Typkonvertierungen und source()-Referenz:

claude "Erstelle ein dbt Staging-Model für diese Tabelle.
Rohstruktur aus dem Warehouse:
- raw_orders: id (int), cust_id (int), order_date (varchar), amt_cents (int), stat (varchar)

Benenne Spalten nach dbt-Konventionen um, konvertiere order_date zu date,
amt_cents zu einem NUMERIC-Betrag in Euro, und verwende source('raw', 'orders')."

Claude Code gibt ein fertiges SQL-Model zurück, das du direkt in models/staging/stg_orders.sql speicherst.

Incremental-Modelle korrekt aufsetzen

Incremental-Modelle sind mächtig, aber die Logik ist fehleranfällig — vor allem bei der ersten Ausführung und beim Umgang mit Late-arriving Data. Claude Code hilft, die Logik sauber zu strukturieren:

claude "Schreibe ein dbt incremental Model für fct_events.
Bedingungen: Partition nach event_date, unique_key ist event_id,
Late-arriving Events bis 3 Tage rückwirkend berücksichtigen.
Warehouse: BigQuery."

Das Ergebnis enthält den richtigen {% if is_incremental() %}-Block, den unique_key-Config und die Filterlogik für das Lookback-Fenster — fertig für BigQuery-Syntax.

Jinja-Macros für wiederverwendbare Logik

Wenn dieselbe Transformation in zehn Models vorkommt, gehört sie in ein Macro. Claude Code schreibt Macros, die parametrisiert und dokumentiert sind:

claude "Schreibe ein dbt Macro 'classify_revenue_tier', das einen revenue-Wert
entgegennimmt und 'low' / 'medium' / 'high' zurückgibt.
Grenzen: low < 1000, medium 1000-9999, high >= 10000.
Füge einen Docstring hinzu."

schema.yml mit Tests und Dokumentation

Das Anlegen von schema.yml ist zeitaufwändig aber wichtig. Claude Code generiert es aus einem vorhandenen Model oder einer Spaltenliste:

claude "Erstelle schema.yml für das Model fct_orders.sql im Ordner models/marts/.
Lies die Datei und füge unique/not_null-Tests für order_id hinzu,
accepted_values für status ('placed','shipped','delivered','cancelled'),
relationships-Test für customer_id zu ref('stg_customers'),
und sinnvolle Beschreibungen für alle Spalten auf Deutsch."

Claude Code liest fct_orders.sql, leitet die Spalten ab und schreibt eine vollständige schema.yml — inklusive Model-Beschreibung, Spalten-Dokumentation und Tests.

Fehler in ref()-Ketten debuggen

Wenn dbt run mit einem kryptischen Fehler abbricht — oft irgendwo in der Mitte einer langen Abhängigkeitskette — ist das Debugging mühsam. Claude Code kann den gesamten Fehler inklusive DAG-Kontext analysieren:

dbt run --select fct_orders+ 2>&1 | claude "Analysiere diesen dbt-Fehler.
Zeige welches Model fehlschlägt, warum, und in welchem upstream Model
die eigentliche Ursache liegt."

Hinweis zu dbt-Fehlern: dbt-Fehlermeldungen benennen oft das Model, in dem der Fehler auftritt — nicht unbedingt das Model, das die fehlerhafte Logik enthält. Ein Column not found-Fehler in fct_orders kann bedeuten, dass ein upstream Staging-Model die Spalte gar nicht erst produziert. Claude Code verfolgt diese Kette.

7. Was Claude Code nicht ersetzt

Claude Code dbt ist ein Beschleuniger, kein Ersatz für SQL-Kenntnisse. Warehouse-spezifische Optimierungen (Clustering-Keys in BigQuery, Micro-Partitioning in Snowflake, Vacuum in Redshift) erfordern Verständnis des jeweiligen Systems. Und die Datenmodellierung selbst — welche Fakten und Dimensionen ein Star-Schema braucht, wie Grain und Granularität definiert werden — ist konzeptuelles Handwerk, das durch KI-Unterstützung leichter wird, aber nicht verschwindet.

Was Claude Code abnimmt: das Tippen, das Suchen nach der richtigen Jinja-Syntax, das Pflegen von YAML-Dateien, das Debuggen von Fehlern, die sich über mehrere Modell-Ebenen erstrecken. Das sind die Stunden, die bei intensiver dbt-Entwicklung akkumulieren — und die produktiver genutzt werden können.


Claude Code Mastery — von dbt bis zum produktiven Agenten

dbt ist ein Beispiel für Claude Codes Stärke bei strukturierten, wiederholbaren Aufgaben. Im Kurs lernst du Agents, MCP-Server, Hooks und Multi-Agent-Workflows — vollständig auf Deutsch, einmalig bezahlt.

Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht

Kurs · Claude Code Mastery

Von dbt-Models zum produktiven AI-Agenten

Data Engineering, Agents, MCP, Hooks, Multi-Agent-Workflows. Alles auf Deutsch, einmalig bezahlt — kein Abo, keine Plattformabhängigkeit.

Jetzt einsteigen → Kursübersicht ansehen →

Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht