Datenqualität mit dbt — Von Tests und Fehlertabellen zur historischen Überwachung
Wie dbt Generic und Custom Data Tests in YAML definiert, fehlerhafte Datensätze mit store_failures persistiert und die Ergebnisse über eine zusätzliche Historientabelle für Qlik, Power BI und Data Governance operationalisiert werden.
Begriffe vor dem Lesen
- DQ auf der Plattform — Umsetzung von Datenqualitaetsregeln in Fabric, dbt, Databricks oder vergleichbaren Stacks.
- Rule-ID — Stabile Kennung einer fachlichen Erwartung ueber Tools hinweg.
- Result Table — Standardisierte Tabelle für Regel-Lauf, Status, Fehlerrate, Owner und Nachweis.
- Quellkorrektur — Behebung im fuehrenden System, wenn der Fehler dort entsteht.
- Transformation — Nachgelagerte Bereinigung; sie braucht Kennzeichnung, Grund und Nachweis.
Qualität, Quellkorrektur und AI-Nutzung
Datenqualität muss sichtbar machen, wo ein Problem behoben wurde. Wenn der Fehler im Quellsystem entsteht, ist die beste Behebung eine Korrektur an der Quelle oder mindestens ein dokumentierter Quellbefund mit Owner. Wenn ETL oder ELT Werte nachgelagert bereinigt, schätzt, mappt oder filtert, braucht diese Änderung Evidence: Regel, Grund, betroffene Felder, Version und erlaubte Nutzung.
Das ist besonders wichtig für AI. Retrieval, Training, Features und Agenten sehen oft nur das nachgelagerte Ergebnis. Ohne Kennzeichnung wissen sie nicht, ob ein Wert beobachtet, korrigiert, geschätzt, defaulted oder ausgeschlossen wurde. Governance muss Unsicherheit und Herkunft erhalten, statt sie hinter einem sauber wirkenden Datensatz zu verstecken.
dbt testet Daten — eine historische Qualitätssteuerung muss ergänzt werden
dbt besitzt ein sehr klares Testprinzip:
Ein Data Test ist eine SQL-Abfrage, die genau die Datensätze zurückgibt, welche eine Regel verletzen.
Liefert die Abfrage keine Zeilen, besteht der Test. Liefert sie fehlerhafte Zeilen, warnt dbt oder bewertet den Test als fehlgeschlagen.
Damit eignet sich dbt sehr gut, um Datenqualitätsregeln direkt mit Modellen, Quellen, Seeds und Snapshots zu verbinden.
dbt löst aber nicht automatisch alle Anforderungen eines operativen Data-Quality-Monitorings:
- Die Standardausgabe konzentriert sich auf den aktuellen Testlauf.
store_failuresspeichert fehlerhafte Datensätze, ersetzt aber die vorherige Fehlertabelle desselben Tests.- Die Fehlertabellen verschiedener Tests besitzen nicht zwingend dieselbe Spaltenstruktur.
- Ein bestandener Test enthält keine Fehlerzeilen, benötigt für die Historie aber trotzdem eine Ergebniszeile.
- Der aktuelle Fehlerzähler allein liefert noch keine vollständige Zeitreihe.
Rows Testedwird von einem normalen dbt Data Test nicht automatisch als standardisierte Kennzahl bereitgestellt.- verantwortliche Person, Data Product, Schweregrad und fachliche Rule ID müssen aus Governance-Metadaten ergänzt werden.
Deshalb besteht das vollständige Muster aus drei getrennten Ebenen:
Die Fehlertabelle erklärt, welche Datensätze aktuell falsch sind. Die Historientabelle zeigt, wie sich die Qualität über viele Läufe entwickelt.
Generic Tests, Custom Generic Tests und Singular Tests
dbt unterscheidet bei Data Tests im Wesentlichen zwischen wiederverwendbaren Generic Tests und einmalig formulierten Singular Tests.
Eingebaute Generic Tests
dbt liefert vier wiederverwendbare Generic Tests aus:
| Test | Bedeutung |
|---|---|
| not_null | Eine Spalte darf keine Nullwerte enthalten |
| unique | Eine Spalte oder ein Ausdruck muss eindeutig sein |
| accepted_values | Werte müssen in einer definierten Werteliste enthalten sein |
| relationships | Werte müssen in einer referenzierten Tabelle vorhanden sein |
Diese Regeln decken viele technische Basisprüfungen ab.
models:
- name: dim_customer
columns:
- name: customer_id
data_tests:
- not_null
- unique
- name: customer_status
data_tests:
- accepted_values:
arguments:
values:
- active
- inactive
- blocked
- name: country_id
data_tests:
- relationships:
arguments:
to: ref('dim_country')
field: country_id
Die ältere Eigenschaft tests: wird aus Kompatibilitätsgründen weiterhin unterstützt. Für neue Projekte ist data_tests: eindeutiger, weil dbt inzwischen zusätzlich Unit Tests kennt.
Custom Generic Tests
Ein Custom Generic Test kapselt wiederverwendbare, organisationsspezifische Logik.
Beispiel: Ein Wert muss innerhalb eines erlaubten Bereichs liegen.
{% test value_between(
model,
column_name,
min_value,
max_value
) %}
select
*
from {{ model }}
where {{ column_name }} < {{ min_value }}
or {{ column_name }} > {{ max_value }}
{% endtest %}
Die Regel wird anschließend in YAML verwendet:
models:
- name: fact_sales
columns:
- name: amount
data_tests:
- value_between:
name: dq_102_sales_amount_range
arguments:
min_value: 0
max_value: 1000000
config:
severity: error
store_failures: true
Custom Generic Tests sind sinnvoll für Regeln wie:
- Wertebereich
- bedingtes Pflichtfeld
- gültige Zeitintervalle
- E-Mail- oder Identifier-Formate
- Vergleich mehrerer Spalten
- Eindeutigkeit einer Spaltenkombination
- fachliche Schwellenwerte
- mandantenabhängige Regeln
- Prüfungen nur für aktive Datensätze
Der Testname sollte stabil und nachvollziehbar sein. Ein Name wie dq_102_sales_amount_range lässt sich leichter mit einer Governance-Regel verknüpfen als ein automatisch zusammengesetzter technischer Name.
Singular Tests
Singular Tests sind eigenständige SQL-Dateien, die fehlerhafte Datensätze zurückgeben.
Beispiel:
-- tests/assert_order_total_matches_components.sql
select
order_id,
order_total,
item_total,
tax_amount
from {{ ref('fact_orders') }}
where order_total <> item_total + tax_amount
Singular Tests passen zu:
- komplexen Regeln über mehrere Modelle
- einmaligen fachlichen Assertions
- Abstimmungen zwischen Fakt- und Aggregattabellen
- Salden- oder Kontrollsummen
- Prüfungen, die nicht sinnvoll parametrisiert werden können
Werden ähnliche Singular Tests mehrfach kopiert, sollte daraus ein Custom Generic Test oder ein generiertes Macro werden.
YAML wird zur ausführbaren Regeldefinition
Die YAML-Datei verbindet Datenmodell und Qualitätsregel.
Sie kann nicht nur den Testnamen und seine Argumente enthalten, sondern auch die operative Behandlung:
models:
- name: fact_sales
description: Governed sales transaction model
columns:
- name: order_id
data_tests:
- not_null:
name: dq_101_order_id_required
config:
severity: error
store_failures: true
tags:
- data_quality
- critical
- unique:
name: dq_103_order_id_unique
config:
severity: error
error_if: "> 0"
warn_if: "> 0"
store_failures: true
- name: amount
data_tests:
- value_between:
name: dq_102_sales_amount_range
arguments:
min_value: 0
max_value: 1000000
config:
severity: error
error_if: "> 100"
warn_if: "> 0"
store_failures: true
Die YAML-Definition legt damit fest:
- welches Modell geprüft wird
- welche Spalte betroffen ist
- welche Testlogik gilt
- welche Parameter verwendet werden
- wie der Test heißt
- ob Fehler gespeichert werden
- wann gewarnt wird
- wann der Lauf fehlschlägt
- welche Tags für Selektion und Betrieb gelten
Rule ID und dbt Test Name
Für kleinere Projekte kann der benutzerdefinierte Testname gleichzeitig als Rule ID dienen.
Für ein Governance-Framework ist eine getrennte Identität robuster:
| Identität | Aufgabe |
|---|---|
| Rule ID | stabile fachliche Identität der Qualitätsregel |
| dbt Test Name | lesbarer und selektierbarer Name der konkreten dbt-Implementierung |
| dbt Unique ID | technische Identität des kompilierten dbt-Knotens |
| Rule Version | Version der fachlichen und technischen Regeldefinition |
Dadurch kann eine Regel technisch neu implementiert werden, ohne ihre fachliche Historie zu verlieren.
Ein Generator kann dieses Mapping zentral verwalten:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
DQ-102
→ dq_102_sales_amount_range
→ test.sales_project.dq_102_sales_amount_range...
→ Rule Version 3
Severity und Schwellenwerte
dbt Data Tests müssen nicht bei jeder einzelnen fehlerhaften Zeile den gesamten Lauf abbrechen.
Die Konfiguration unterstützt unter anderem:
severity: errorseverity: warnerror_ifwarn_if
Beispiel:
data_tests:
- unique:
name: dq_103_order_id_unique
config:
severity: error
error_if: "> 100"
warn_if: "> 0"
Die Logik bedeutet:
- mehr als 100 Fehler → Error
- 1 bis 100 Fehler → Warning
- 0 Fehler → Pass
Diese technische Schwelle muss zur fachlichen Severity passen.
Eine kritische Regel kann beispielsweise bereits bei einer einzigen Verletzung fehlschlagen. Eine weniger kritische Vollständigkeitsregel kann zunächst warnen und erst oberhalb eines definierten Grenzwerts blockieren.
fail_calc bestimmt den Fehlerzähler
Standardmäßig zählt dbt die von der Testabfrage zurückgegebenen Zeilen.
Bei einem Eindeutigkeitstest kann eine zurückgegebene Zeile jedoch eine mehrfach vorkommende Schlüsselgruppe repräsentieren. Die tatsächliche Anzahl betroffener Datensätze kann höher sein.
Mit fail_calc kann der Fehlerzähler angepasst werden:
data_tests:
- unique:
config:
fail_calc: >
case
when count(*) > 0 then sum(n_records)
else 0
end
Damit muss klar dokumentiert werden, was Rows Failed bedeutet:
- Anzahl fehlerhafter Schlüsselgruppen
- Anzahl aller Datensätze in fehlerhaften Gruppen
- Anzahl zusätzlicher Duplikate über das erste Vorkommen hinaus
Die Semantik darf sich für dieselbe Rule ID nicht unkontrolliert ändern.
store_failures speichert Evidenz, aber keine Historie
Mit store_failures: true persistiert dbt die fehlerhaften Datensätze eines Tests in der Datenplattform.
models:
- name: dim_customer
columns:
- name: email
data_tests:
- not_null:
name: dq_201_customer_email_required
config:
store_failures: true
Standardmäßig verwendet dbt dafür ein Audit-Schema, dessen Name typischerweise auf _dbt_test__audit endet.
Die gespeicherte Relation verwendet den Namen des Tests beziehungsweise einen konfigurierten Alias.
Das bietet einen unmittelbaren operativen Vorteil:
- fehlerhafte Datensätze sind direkt abfragbar
- Data Engineers können die Ursache analysieren
- Business Keys können identifiziert werden
- technische Fehlermuster werden sichtbar
- nachgelagerte Prozesse können auf die aktuelle Fehlerliste zugreifen
Die entscheidende Einschränkung lautet:
Die Fehlerrelation eines Tests ersetzt bei jedem neuen Lauf den vorherigen Inhalt.
Auch ein bestandener Folgelauf ersetzt die vorherigen Fehler.
Damit beantwortet store_failures:
Welche Datensätze verletzen die Regel im aktuellen Testlauf?
Es beantwortet nicht:
Wie viele Fehler hatte dieselbe Regel gestern, letzte Woche oder vor der letzten Korrektur?
Failure Table und History Table haben unterschiedliche Grains
Die beiden Tabellen dürfen nicht verwechselt werden.
Failure Table
Grain:
Eine Zeile je aktuell fehlerhaftem Datensatz oder je fehlerhafter Gruppe.
Typische Inhalte:
- Business Key
- geprüfter Wert
- Vergleichswert
- Fehlergrund
- technische Quellspalten
- weitere durch den Test zurückgegebene Evidenz
Die Struktur kann sich je Test unterscheiden.
DQ History Table
Grain:
Eine Zeile je Rule ID, dbt-Test und Ausführung.
Empfohlene Struktur:
| Feld | Herkunft |
|---|---|
| Run ID | invocation_id oder Orchestrator |
| Rule ID | Regelregistry oder Generator |
| Platform | dbt plus Zielplattform |
| Data Product | Governance-Metadaten |
| Table | dbt Node beziehungsweise Modell |
| Column | Testmetadaten |
| Test Type | Testname oder normalisierter Typ |
| Status | dbt Result Status |
| Rows Tested | zusätzliche Messabfrage |
| Rows Failed | dbt Result failures oder kontrollierter fail_calc |
| Failure Rate | berechnete Kennzahl |
| Executed At | Run-Zeitpunkt |
| Owner | Regelregistry |
| Severity | Governance- und dbt-Konfiguration |
| Execution Time | dbt Result |
| dbt Unique ID | run_results.json und manifest.json |
| Failure Relation | gespeicherte Audit-Relation |
| Message | dbt Result Message |
Ein bestandener Test erzeugt ebenfalls eine Historienzeile:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
Rows Failed = 0
Status = Passed
Ohne diese Zeile würde das Monitoring nur Fehler sehen und könnte keine Pass Rate oder stabile Zeitreihe berechnen.
dbt liefert nicht automatisch Rows Tested
Ein dbt Data Test gibt primär fehlerhafte Datensätze und einen Fehlerzähler zurück.
Die Anzahl aller geprüften Datensätze ist nicht automatisch Bestandteil des normalen Testergebnisses.
Für die Ergebnisstruktur aus Part 1 muss sie deshalb ergänzt werden.
Variante 1: Separate Scope-Abfrage
Der History Generator kennt Modell, Spalte und einen möglichen where-Filter und berechnet:
select count(*) as rows_tested
from {{ ref('fact_sales') }}
where <identischer Test-Scope>
Vorteil:
- klare und allgemeine Kennzahl
Nachteil:
- zusätzliche Abfrage und zusätzlicher Compute
Variante 2: Generierte Messlogik
Der DG Macro Generator erzeugt neben der eigentlichen Fehlerabfrage eine standardisierte Messabfrage.
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
Failure Query
→ liefert fehlerhafte Datensätze
Metric Query
→ liefert Rows Tested und Rows Failed
Vorteil:
- konsistente Semantik
- bessere Optimierung
- zentrale Kontrolle der Messdefinition
Variante 3: Regelabhängige Kennzahl
Nicht jede Regel prüft Datensätze.
Bei einer Aktualitätsregel kann gelten:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
Rows Tested = 1
Rows Failed = 0 oder 1
Bei einer Abstimmungsregel kann Rows Tested die Anzahl verglichener Gruppen statt die Anzahl einzelner Transaktionen darstellen.
Deshalb muss die Regelregistry zusätzlich den Metric Grain beschreiben.
Drei Wege zur Historisierung
1. dbt-Artefakte nach jedem Lauf einlesen
dbt erzeugt run_results.json mit Informationen zu ausgeführten Nodes, darunter:
unique_id- Status
- Fehlerzahl
- Laufzeit
- Timing
- Nachricht
- Relation der gespeicherten Fehler, sofern vorhanden
Das manifest.json liefert ergänzende Metadaten zu Modellen, Tests, Abhängigkeiten und Konfigurationen.
Ein nachgelagerter Prozess kann beide Artefakte verbinden:
Dies ist meist die robusteste plattformneutrale Variante.
Vorteile:
- klare Trennung zwischen dbt-Ausführung und Monitoring
- keine zusätzlichen Inserts innerhalb des Testlaufs
- Artefakte können zentral über mehrere Projekte konsolidiert werden
- technische Fehler werden ebenfalls sichtbar
- Historisierung kann unabhängig versioniert werden
Die Artefakte müssen pro Invocation gesichert werden. Wird nur die letzte lokale Datei aus target/ behalten, entsteht erneut keine Historie.
2. on-run-end Hook
Im on-run-end-Kontext stellt dbt die Result-Objekte der ausgeführten Ressourcen bereit.
Ein vereinfachtes Muster:
{% macro persist_dq_history(results) %}
{% if execute %}
{% for result in results
if result.node.resource_type == 'test' %}
{% set rows_failed =
result.failures
if result.failures is not none
else 0
%}
{% set insert_sql %}
insert into governance.dq_test_history (
run_id,
dbt_unique_id,
test_name,
test_status,
rows_failed,
execution_time,
executed_at
)
values (
'{{ invocation_id }}',
'{{ result.node.unique_id }}',
'{{ result.node.name }}',
'{{ result.status }}',
{{ rows_failed }},
{{ result.execution_time }},
'{{ run_started_at }}'
)
{% endset %}
{% do run_query(insert_sql) %}
{% endfor %}
{% endif %}
{% endmacro %}
Aktivierung:
on-run-end:
- "{{ persist_dq_history(results) }}"
Das Beispiel zeigt nur das Prinzip. Eine produktive Umsetzung benötigt:
- adaptergerechtes Quoting
- sichere Behandlung von Nachrichten und Sonderzeichen
- Mapping der dbt-Statuswerte
- Rule-ID- und verantwortliche Person-Anreicherung
- Fehlerbehandlung des Hooks
- Verhalten bei Transaktionen und Rollbacks
- Versionierung des Zielschemas
- Berechnung von
Rows Tested - Vermeidung doppelter Inserts bei Wiederholungen
3. Inkrementelles History Model
Eine zusätzliche dbt-Ausführung liest normalisierte Run-Metadaten oder eine Staging-Tabelle und hängt neue Resultate inkrementell an.
{{ config(
materialized='incremental',
unique_key=['run_id', 'dbt_unique_id']
) }}
select
run_id,
rule_id,
dbt_unique_id,
test_status,
rows_tested,
rows_failed,
failure_rate,
executed_at
from {{ ref('stg_dbt_test_results') }}
{% if is_incremental() %}
where executed_at >
(
select coalesce(max(executed_at), '1900-01-01')
from {{ this }}
)
{% endif %}
Das Modell darf nicht nur die aktuellen store_failures-Tabellen lesen, weil bestandene Tests dort keine historischen Fehler mehr besitzen.
Es benötigt einen persistenten Eingang aus:
- Artefakt-Loader
- on-run-end Staging
- Orchestrator-API
- Event- oder Log-Export
Die invocation_id als Run ID
dbt erzeugt für jeden Command eine UUID namens invocation_id.
Sie eignet sich als technische Run ID:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
dbt invocation
→ invocation_id
→ mehrere Modelle und Tests
→ gemeinsame Run-Gruppe
Bei einer übergeordneten Orchestrierung kann zusätzlich eine fachliche Batch-ID sinnvoll sein:
| Feld | Beispiel |
|---|---|
| dbt Invocation ID | konkrete Ausführung von dbt build oder dbt test |
| Pipeline Run ID | gesamter Ablauf aus Ingestion, dbt, Export und Reporting |
| Business Batch ID | fachlicher Verarbeitungstag oder Monatsabschluss |
Die Historientabelle kann alle drei Identitäten speichern.
Statuswerte normalisieren
dbt und das plattformübergreifende DQ-Modell können unterschiedliche Statuswerte verwenden.
Ein mögliches Mapping:
| dbt Status | Standardstatus |
|---|---|
pass |
Passed |
warn |
Warning |
fail |
Failed |
error |
Error |
skipped |
Skipped |
warn sollte nicht automatisch mit Failed zusammengefasst werden.
Eine Warning bedeutet:
- die Regel wurde ausgeführt
- ein definierter Warnschwellenwert wurde verletzt
- der Error-Schwellenwert wurde nicht überschritten
- die Ausführung darf gemäß Konfiguration fortgesetzt werden
Qlik und Power BI sollten Warnungen separat darstellen.
DG Tools als regelgetriebene Automatisierung
Die DG Tools verschieben die Arbeit von wiederholtem Handcoding zu einer zentralen Regeldefinition.
Die Toolchain besitzt drei getrennte Aufgaben.
DG Macro Generator
Der DG Macro Generator erstellt wiederverwendbare Custom Generic Tests.
Mögliche Eingaben:
- Test Type
- unterstützte Datentypen
- Rule Arguments
- Fehlerbedingung
- optionaler Umfang
- Fail Calculation
- adapterabhängige SQL-Variante
- standardisierte Evidenzspalten
Mögliche Ausgaben:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
tests/generic/value_between.sql
tests/generic/required_when.sql
tests/generic/valid_date_interval.sql
tests/generic/unique_combination.sql
Der Generator sollte sicherstellen:
- einheitliche Benennung
- konsistente Parameter
- identische Nullbehandlung
- kontrollierte
fail_calc-Semantik - dokumentierte Ergebnisstruktur
- Wiederverwendbarkeit über Projekte
- optionales Adapter Dispatching
DQ Rules Generator
Der DQ Rules Generator übersetzt Governance-Regeln in ausführbare YAML-Definitionen.
Eingaben können stammen aus:
- zentralem Rule Repository
- Spreadsheet
- Data-Governance-Portal
- Data-Product-Konfiguration
- versionierter YAML- oder JSON-Datei
Die generierte Definition enthält beispielsweise:
- Rule ID
- dbt Test Name
- Modell und Spalte
- Test Type
- Argumente
- Threshold
- Schweregrad
- verantwortliche Person
- Data Product
- Tags
store_failures- Aktivstatus
- Rule Version
Ausgabe:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
models/customer/schema.yml
models/sales/schema.yml
models/finance/schema.yml
Damit werden Governance-Regeln reproduzierbar in dbt überführt.
DQ History Generator
Der DQ History Generator baut die operative Ergebnisschicht.
Er kann erzeugen:
- Schema für
DQ_TEST_HISTORY - Artefakt-Staging
- Mapping aus dbt Unique ID zu Rule ID
on-run-endMacro- inkrementelles History Model
- Statusnormalisierung
- Berechnung von
Rows Tested - Berechnung von Failure Rate
- View für Qlik und Power BI
- optionale Failure-Detail-Referenzen
Eine mögliche Struktur:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
models/dq/stg_dbt_run_results.sql
models/dq/int_dbt_test_metrics.sql
models/dq/dq_test_history.sql
models/dq/v_dq_monitoring.sql
macros/dq/persist_dq_results.sql
Eine zentrale Rule Definition als Single Source of Truth
Ein regelgetriebener Ansatz trennt Definition und Generierung.
Beispiel:
rule_id: DQ-102
name: Sales amount within accepted range
data_product: Sales
owner: Data Steward Sales
severity: High
target:
model: fact_sales
column: amount
test:
type: value_between
arguments:
min_value: 0
max_value: 1000000
thresholds:
warn_if: "> 0"
error_if: "> 100"
execution:
engine: dbt
store_failures: true
history:
rows_tested_strategy: model_count
enabled: true
version: 3
Daraus entstehen:
Die Regeldefinition ist damit nicht nur Dokumentation. Sie ist die Quelle für Code, Ausführung und Monitoring.
Failure Tables standardisieren, ohne Evidenz zu verlieren
dbt speichert grundsätzlich die Spalten, welche die jeweilige Testabfrage zurückgibt.
Das ist für die Ursachenanalyse hilfreich, führt aber zu heterogenen Fehlertabellen.
Ein Not-Null-Test kann zurückgeben:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
customer_id
email
source_system
Ein Duplikattest kann zurückgeben:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
order_id
n_records
Ein Beziehungen-Test kann zurückgeben:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
product_id
Die Failure Tables müssen daher nicht in ein starres gemeinsames Detailformat gezwungen werden.
Besser ist eine Trennung:
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
DQ_TEST_HISTORY
→ vollständig standardisiert
DBT_TEST__AUDIT.*
→ testspezifische Evidenz
DQ_FAILURE_INDEX
→ standardisierter Verweis auf die Evidenz
Ein Failure Index kann enthalten:
- Run ID
- Rule ID
- dbt Unique ID
- Failure Relation
- Anzahl gespeicherter Fehlerzeilen
- Business-Key-Spalte
- Retention-Klasse
- personenbezogene Daten-Klassifikation
- Details URI
So bleibt das Monitoring einheitlich, ohne die fachliche Evidenz zu verlieren.
Datenschutz und Aufbewahrung
store_failures kann personenbezogene oder vertrauliche Werte duplizieren.
Deshalb müssen für Audit-Tabellen Regeln gelten:
- nur erforderliche Spalten zurückgeben
- personenbezogene Daten möglichst maskieren oder hashen
- Business Key statt vollständigem Datensatz speichern
- Zugriff auf das Audit-Schema einschränken
- Aufbewahrungsdauer definieren
- Entwicklungs- und Produktionsschemas trennen
- sehr große Fehlermengen begrenzen
- Fehlerrelationen nach Rule ID klassifizieren
Ein Custom Generic Test sollte nicht pauschal select * verwenden, wenn für die Behebung nur drei Spalten benötigt werden.
Qlik und Power BI konsumieren die Historie
Qlik und Power BI sollten nicht direkt alle heterogenen Audit-Tabellen laden.
Die bevorzugte Architektur lautet:
Typische Auswertungen:
- Failure Rate over Time
- Rule Pass Rate
- Warnungen und Fehler nach Schweregrad
- fehlgeschlagene Regeln nach Data Product
- wiederkehrende Fehler nach Rule ID
- Laufzeit je Test
- aktuelle Failure Relation
- letzte erfolgreiche Ausführung
- Tests ohne aktuellen Lauf
- Zeit zwischen Fehler und Behebung
- Re-Test nach Korrektur
Zeilenfehlerrate
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
Sum(Rows Failed) / Sum(Rows Tested)
Regel-Pass-Rate
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
Passed Tests / Executed Tests
Execution Coverage
Beispiel (Lehrfall, keine Kundendaten): Typisches Muster aus Governance-Projekten — im eigenen Umfeld durch Catalog-/BI-/Ticket-/Prozessquellen ersetzen.
Executed Active Rules / Active Rules
Coverage ist wichtig. Ein scheinbar grünes Dashboard ist wertlos, wenn ein Teil der aktiven Regeln gar nicht ausgeführt wurde.
Praktisches dbt-Zielbild
Ein produktiver Aufbau kann folgende Strukturen verwenden:
Empfohlene Komponenten:
| Komponente | Aufgabe |
|---|---|
| Rule Repository | fachliche Regel, Owner, Severity, Version |
| DG Macro Generator | wiederverwendbare Testlogik |
| DQ Rules Generator | ausführbare YAML-Instanzen |
| dbt Data Tests | technische Ausführung |
| store_failures | aktuelle fehlerhafte Datensätze |
| Artifact Loader / Hook | Resultate je Invocation erfassen |
| DQ History Generator | standardisierte Historie |
| Monitoring View | BI-freundliche Ergebnisschicht |
Ein sinnvoller erster Sprint
- Eine dbt-Anwendung mit vier Regeln auswählen.
- Stabile Rule IDs und benutzerdefinierte Testnamen vergeben.
store_failuresfür kritische Regeln aktivieren.- Fehlerrelationen in ein kontrolliertes Audit-Schema schreiben.
run_results.jsonundmanifest.jsonje Invocation sichern.- Eine Staging-Tabelle für Testresultate aufbauen.
Rows Testedfür die vier Regeln eindeutig definieren.- Eine append-orientierte
DQ_TEST_HISTORYerzeugen. - Status, Owner, Severity und Data Product ergänzen.
- Eine Monitoring View für Qlik oder Power BI bereitstellen.
- Danach die drei Generatoren schrittweise einsetzen.
Der erste Prototyp sollte den vollständigen vertikalen Ablauf beweisen:
Typische Fehlentscheidungen
store_failures mit Historisierung verwechseln
Die Audit-Tabelle enthält den aktuellen Fehlerbestand und ersetzt vorherige Ergebnisse.
Nur fehlgeschlagene Tests speichern
Dadurch fehlen bestandene Läufe und eine korrekte Pass Rate.
Rows Failed ohne Semantik verwenden
Bei Duplikaten kann eine Zeile eine Gruppe oder viele Datensätze repräsentieren.
Rows Tested aus dem dbt-Resultat erwarten
Diese Kennzahl muss normalerweise zusätzlich berechnet werden.
Automatisch generierte Testnamen als dauerhafte Governance-ID verwenden
Änderungen an Argumenten oder Modellen können technische Identitäten verändern. Eine stabile Rule ID sollte separat verwaltet werden.
Alle Audit-Tabellen direkt in Qlik oder Power BI laden
Die Strukturen sind testspezifisch und nicht als gemeinsames Faktenmodell gedacht.
Fehlerdetails unbegrenzt speichern
Audit-Tabellen können groß werden und sensible Daten enthalten.
DG Tools nur als Codegenerator betrachten
Der entscheidende Nutzen liegt nicht nur in weniger Handarbeit. Die Generatoren erzwingen einen gemeinsamen Regelvertrag von Governance über Ausführung bis Historie.
Die zentrale Erkenntnis
dbt liefert eine starke Test-Engine und kann aktuelle Fehler direkt persistieren. Für echte Operational Data Quality benötigt es zusätzlich eine append-orientierte Historientabelle.
Generic Tests und Custom Tests bilden die ausführbare Regel.
YAML verbindet die Regel mit Modellen, Argumenten, Severity, Schwellenwerten und store_failures.
Audit-Tabellen speichern die aktuelle Evidenz.
run_results.json, manifest.json, invocation_id und der on-run-end-Kontext liefern die technischen Metadaten für eine Historisierung.
Die DG Tools automatisieren anschließend die vollständige Kette:
Damit wird aus einzelnen dbt-Tests eine regelgetriebene, versionierte und in Qlik oder Power BI auswertbare Data-Quality-Plattform.
Passende Playbooks
- Part 1 — From Tests to Data Quality Monitoring
- Part 2 — Data Quality in Microsoft Fabric
- Welche Rolle dbt spielt
- The Missing Pieces — Data Quality
- Data Quality & Governance
Quellen und weiterführende Dokumentation
- dbt — Add Data Tests to Your DAG
- dbt — Data Tests Property
- dbt — store_failures
- dbt — fail_calc
- dbt — severity, error_if and warn_if
- dbt — Run Results JSON
- dbt — on-run-end Context
- dbt — invocation_id
Stand der Funktionsbeschreibung: Juli 2026. dbt-Syntax, unterstützte Konfigurationen und Artefaktschemas können sich zwischen dbt Core, Fusion und der dbt-Plattform verändern. Für die konkrete Implementierung sollte die Dokumentation der eingesetzten Version geprüft werden.
DQ on the platform
Part 2 of 5
View series