Daten im SQL Server validieren
Ein praktischer Leitfaden zur Datenvalidierung in Microsoft SQL Server — die sechs Prüfungen, die jede Tabelle braucht, das T-SQL dazu, und wie daraus ein versionierter Data Contract wird, der nach Zeitplan läuft.
· 8 min read
Der schnellste Weg, Daten im SQL Server zu validieren, besteht darin, jede Erwartung als einzelne Aggregatabfrage zu formulieren, die eine Anzahl von Verstößen zurückgibt, alle Abfragen in einem Durchgang gegen die Tabelle laufen zu lassen und den Lauf fehlschlagen zu lassen, sobald eine Anzahl ihren Schwellenwert überschreitet. Sechs Prüfungen decken die meisten realen Ausfälle ab: NULL-Werte in Pflichtspalten, doppelte Schlüssel, Werte außerhalb einer erlaubten Menge, Zahlen außerhalb eines plausiblen Bereichs, fehlerhaft formatierte Zeichenketten und veraltete Zeilen. Dieser Leitfaden zeigt das T-SQL für jede davon, die Eigenheiten des SQL Server, die Ihnen zum Verhängnis werden, und den Weg von Ad-hoc-Skripten zu einem Contract, der nach Zeitplan läuft.
Warum SQL Server einen eigenen Ansatz braucht
Die meisten Ratschläge zur Datenqualität sind für Postgres geschrieben und setzen stillschweigend Dinge voraus, die T-SQL nicht hat. Drei Unterschiede zählen:
- Es gibt keinen Operator für reguläre Ausdrücke.
LIKEist die einzige Mustererkennung ab Werk. Es unterstützt Zeichenklassen wie[0-9]sowie die Platzhalter%und_— genug für verankerte Muster mit fester Form, und nicht mehr. - Die Zeilenbegrenzung heißt
TOP n, nichtLIMIT n, und sie steht vor der Select-Liste statt am Ende der Anweisung. Jedes Werkzeug, das Beispielabfragen baut, muss das wissen. - Die Collation entscheidet über Gleichheit. Eine Spalte mit der Standard-Collation
SQL_Latin1_General_CP1_CI_ASbehandelt'ACTIVE'und'active'als denselben Wert. Eine Collation mit Beachtung der Groß-/Kleinschreibung tut das nicht. Ihre Prüfung auf „erlaubte Werte" bedeutet auf zwei Servern also stillschweigend Verschiedenes.
Alles Folgende ist mit diesen Punkten im Hinterkopf geschrieben. Für die Teile, die auf jeder Engine gleich sind — wo Prüfungen laufen sollten, wie man sie plant, welche Tabellen Vorrang haben —, beginnen Sie mit dem vollständigen Leitfaden zur Datenvalidierung.
Die sechs Prüfungen, die jede Tabelle braucht
1. Vollständigkeit — NULL-Werte in Pflichtspalten
SELECT COUNT_BIG(*) AS violations
FROM [sales].[orders]
WHERE [order_id] IS NULL;
Verwenden Sie auf großen Faktentabellen COUNT_BIG statt COUNT: COUNT liefert einen int und läuft jenseits von 2,1 Milliarden Zeilen über. Beachten Sie außerdem, dass COUNT(column) NULL-Werte bereits überspringt — deshalb ist die Prüfung als gefiltertes COUNT(*) geschrieben. Die beiden sind leicht zu verwechseln, und die falsche Variante meldet immer null Verstöße.
2. Eindeutigkeit — doppelte Geschäftsschlüssel
SELECT COUNT_BIG(*) AS violations
FROM (
SELECT [order_id]
FROM [sales].[orders]
WHERE [order_id] IS NOT NULL
GROUP BY [order_id]
HAVING COUNT(*) > 1
) AS dupes;
Ein Primärschlüssel-Constraint würde das verhindern, aber Analysetabellen werden meist von einem ELT-Job in einen Heap ohne jedes Constraint geladen. Die Duplikatprüfung ist das, was ein fehlendes Constraint Sie kostet.
3. Konformität — Werte außerhalb einer erlaubten Menge
SELECT COUNT_BIG(*) AS violations
FROM [sales].[orders]
WHERE [status] IS NOT NULL
AND [status] NOT IN ('pending', 'paid', 'shipped', 'refunded');
Lassen Sie die Absicherung mit IS NOT NULL stehen. NOT IN mit einem NULL-Wert auf der linken Seite ergibt UNKNOWN, die Zeile fällt heraus, und eine Spalte, die zu 40 % NULL ist, wirkt vollkommen konform.
4. Genauigkeit — Zahlen außerhalb eines plausiblen Bereichs
SELECT COUNT_BIG(*) AS violations
FROM [sales].[orders]
WHERE [total_amount] IS NOT NULL
AND ([total_amount] < 0 OR [total_amount] > 100000);
Bereichsprüfungen fangen Einheitenfehler ab — Cent als Euro geladen, ein durch eine Währungsumrechnung verschobenes Komma —, die kein Schema-Constraint je zu sehen bekommt.
5. Konformität — fehlerhaft formatierte Bezeichner
Hier weicht T-SQL ab. Es gibt keinen ~-Operator, ein verankertes Muster muss also als LIKE ausgedrückt werden:
-- ^ORD-[0-9]{6}$ becomes:
SELECT COUNT_BIG(*) AS violations
FROM [sales].[orders]
WHERE [reference] IS NOT NULL
AND [reference] NOT LIKE 'ORD-[0-9][0-9][0-9][0-9][0-9][0-9]';
LIKE ist an beiden Enden implizit verankert, wenn das Muster kein führendes oder abschließendes % enthält — das ist also ein echtes Äquivalent zur verankerten Regex. Nicht ausdrücken lassen sich Alternativen, optionale Gruppen, Rückverweise und unbegrenzte Wiederholungen. Dafür greifen Sie besser auf eine explizite Liste erlaubter Werte oder eine handgeschriebene customSql-Prüfung zurück, statt so zu tun, als wäre LIKE eine Regex-Engine.
Catalyst übernimmt diese Übersetzung für Sie: Eine regex-Regel auf einer SQL-Server-Verbindung wird in das entsprechende LIKE-Muster überführt, sofern sie sich ausdrücken lässt, und löst andernfalls einen expliziten Fehler „auf diesem Dialekt nicht unterstützt" aus — die Prüfung scheitert also lautstark, statt stillschweigend durchzulaufen.
6. Aktualität — Freshness
SELECT COUNT_BIG(*) AS violations
FROM [sales].[orders]
WHERE [created_at] < DATEADD(HOUR, -24, SYSUTCDATETIME());
Verwenden Sie SYSUTCDATETIME(), nicht GETDATE(). GETDATE() liefert die lokale Zeit des Servers, dieselbe Prüfung verschiebt sich also zweimal im Jahr um eine Stunde und über Regionen hinweg um ganze Stunden. Speichern Sie Zeitstempel als datetime2 und vergleichen Sie in UTC.
Einen sicheren Nur-Lese-Login einrichten
Validierung sollte nie Schreibzugriff brauchen. Ein minimaler Login sieht so aus:
CREATE LOGIN catalyst_ro WITH PASSWORD = '<generated>';
CREATE USER catalyst_ro FOR LOGIN catalyst_ro;
ALTER ROLE db_datareader ADD MEMBER catalyst_ro;
GRANT VIEW DEFINITION TO catalyst_ro; -- needed to read INFORMATION_SCHEMA
db_datareader gewährt SELECT auf jeder Tabelle; VIEW DEFINITION ist das, was dem Konto erlaubt, Spalten und Typen aus INFORMATION_SCHEMA.COLUMNS aufzulisten. Richten Sie den Login auf ein lesbares sekundäres Replikat, wenn Sie eine Availability Group betreiben — Validierungsabfragen sind Aggregat-Scans und gehören von der Primärinstanz herunter.
Von Ad-hoc-SQL zum Data Contract
Skripte wie die obigen verrotten. Sie liegen in irgendjemandes Repository, niemand weiß, welche davon noch laufen, und die Schwellenwerte sind für die Analystinnen und Analysten, die darauf angewiesen sind, unsichtbar. Die Lösung besteht darin, die Erwartungen deklarativ zu formulieren, in einem Format, das Menschen wie Werkzeuge lesen können.
Catalyst nutzt dafür den Open Data Contract Standard (ODCS). Aus den sechs Prüfungen von oben wird:
apiVersion: v3.0.0
kind: DataContract
info:
title: orders
version: 1.2.0
owner: data-platform
schema:
- name: orders
physicalName: orders
physicalType: table
properties:
- name: order_id
logicalType: string
physicalType: uniqueidentifier
required: true
primaryKey: true
quality:
- rule: nullCount
dimension: completeness
severity: error
mustBe: "0"
- rule: duplicateCount
dimension: uniqueness
severity: error
mustBe: "0"
- name: status
logicalType: string
quality:
- rule: validValues
dimension: conformity
severity: error
mustBe: "['pending', 'paid', 'shipped', 'refunded']"
- name: total_amount
logicalType: number
quality:
- rule: between
dimension: accuracy
severity: error
mustBe: "[0, 100000]"
- name: reference
logicalType: string
quality:
- rule: regex
dimension: conformity
severity: warning
mustBe: "'^ORD-[0-9]{6}#39;"
- name: created_at
logicalType: timestamp
quality:
- rule: freshness
dimension: timeliness
severity: error
mustBe: "<= 24h"
Das YAML ist die Quelle der Wahrheit. Catalyst kompiliert jeden quality-Eintrag in das dialektkorrekte T-SQL von oben, führt den Lauf gegen Ihren Server aus und protokolliert pro Prüfung pass/warn/fail. Wird eine Regel im visuellen Builder bearbeitet, schreibt Catalyst dasselbe YAML zurück, Kommentare und Reihenfolge intakt — der im Pull Request geprüfte Contract ist also der Contract, der läuft.
Beachten Sie das Feld severity. error lässt den Lauf scheitern; warning protokolliert den Verstoß und macht weiter. Musterprüfungen auf manuell erfassten Feldern sind üblicherweise Warnungen — Sie wollen den Trend, nicht einen Pager-Alarm um 3 Uhr nachts.
Zeitplanung und Alarmierung
Eine Validierung, die Sie von Hand starten, ist eine Validierung, die Sie einmal starten. Richten Sie einen Zeitplan auf das Dataset — stündlich für Freshness auf einer Streaming-Tabelle, täglich nach dem ELT-Fenster für alles andere — und alarmieren Sie beim Übergang, nicht beim Zustand. Wichtig ist „Orders hat angefangen zu scheitern", nicht „Orders scheitert immer noch"; Letzteres ist genau das, was Menschen beibringt, den Channel zu ignorieren.
Zwei betriebliche Hinweise speziell für SQL Server:
- Setzen Sie ein Abfrage-Timeout. Ein
COUNT_BIG(*)über eine nicht indizierte Milliarden-Zeilen-Heap-Tabelle läuft bereitwillig eine Stunde. Catalyst wendet pro Prüfung ein Timeout an und meldet die Prüfung alserror(unterschieden vonfail), damit ein Infrastrukturproblem nie wie ein Datenproblem aussieht. - Behalten Sie den Plan Cache im Auge. Parameterlose Aggregat-Scans sind billig zu kompilieren und teuer auszuführen. Validieren Sie auf sehr großen Tabellen lieber eine Partition statt der ganzen Tabelle, oder arbeiten Sie gegen eine gefilterte indizierte Sicht.
SQL-Server-Stolperfallen, die Sie kennen sollten
| Falle | Was passiert | Was zu tun ist |
|---|---|---|
Überlauf bei COUNT(*) | Scheitert jenseits von 2,1 Mrd. Zeilen | COUNT_BIG(*) verwenden |
NOT IN mit NULL-Werten | Zeilen werden stillschweigend ausgeschlossen | IS NOT NULL ergänzen |
GETDATE() | Lokale Serverzeit | SYSUTCDATETIME() verwenden |
| Collation ohne Groß-/Kleinschreibung | 'PAID' besteht eine Prüfung auf 'paid' | Collation festlegen oder mit COLLATE normalisieren |
| Implizite Konvertierung | WHERE varchar_col = 123 scannt die ganze Tabelle | Gleiche Typen vergleichen |
Gleichheit bei float | Bereichsgrenzen durch Rundung verfälscht | Für Geldbeträge decimal verwenden |
Häufig gestellte Fragen
Kann ich Daten im SQL Server validieren, ohne SQL zu schreiben?
Ja. Definieren Sie die Erwartung deklarativ — Pflichtfeld, eindeutig, erlaubte Werte, Zahlenbereich, Muster, maximales Alter — und lassen Sie das Werkzeug sie nach T-SQL kompilieren. Catalyst importiert die Spalten und Typen aus INFORMATION_SCHEMA, schlägt aus dem Schema einen Basissatz an Regeln vor und erzeugt die Abfragen. SQL schreiben Sie nur noch für wirklich maßgeschneiderte Logik, über eine customSql-Regel.
Braucht die Validierung der Datenqualität Schreibzugriff auf meine Datenbank?
Nein. Jede Prüfung in diesem Leitfaden ist ein SELECT, das eine einzige Zahl zurückgibt. Ein db_datareader-Login plus VIEW DEFINITION genügt. Catalyst verbindet sich ausschließlich lesend und speichert nur Metadaten und Prüfergebnisse — die Zeilen selbst bleiben auf Ihrem Server.
Wie prüfe ich reguläre Ausdrücke in T-SQL?
Direkt gar nicht — SQL Server hat keinen Regex-Operator. Verankerte Muster fester Länge lassen sich in LIKE mit Zeichenklassen im Stil von [0-9] übersetzen. Alles, was Alternativen, optionale Gruppen oder unbegrenzte Wiederholungen nutzt, muss zu einer Liste erlaubter Werte, einer CLR-Funktion oder einer eigenen SQL-Prüfung werden.
Wie oft sollten Validierungen laufen?
Richten Sie den Zeitplan nach dem Takt der Daten selbst und führen Sie die Prüfung direkt nach dem Ladevorgang aus, der sie erzeugt. Freshness-Regeln auf Streaming-Tabellen wollen stündliche Läufe; Batch-Dimensionstabellen wollen einen Lauf nach Abschluss des nächtlichen ELT. Häufiger zu prüfen, als sich die Daten ändern, erzeugt nur Rauschen.
Funktioniert das mit Azure SQL und Microsoft Fabric?
Azure SQL Database nutzt dieselbe T-SQL-Oberfläche, alles hier gilt also unverändert. Auch das Warehouse und der SQL-Analytics-Endpunkt von Microsoft Fabric sprechen T-SQL — mit demselben Fehlen von Regex. Die Unterschiede rund um die Entra-ID-Authentifizierung und die OneLake-Metadatensynchronisation finden Sie im Leitfaden zu Microsoft Fabric.