JSON mit T-SQL auswerten
Neues in SQL Server 2025, Teil 2
Relationale Datenbanken speichern strukturierte Informationen: Kunden, Aufträge, Artikel. Moderne Anwendungen liefern dagegen häufig Ereignisse, Zustände oder komplette Requests – und diese kommen fast immer als JSON. Web-APIs, Webhooks, Message-Queues oder Event-Streaming-Systeme verwenden ein Dokumentformat, während die Datenbank weiterhin tabellarisch arbeitet. Die zentrale Frage lautet daher nicht mehr, ob JSON gespeichert werden kann, sondern ob es sich direkt in der Datenbank auswerten lässt.
SQL Server unterstützt JSON seit mehreren Versionen. Während ältere Versionen JSON ausschließlich als NVARCHAR behandelten, besitzt SQL Server 2025 zusätzlich einen nativen JSON-Datentyp. Dieser speichert Dokumente strukturiert und erlaubt effizientere Auswertungen, ohne dass das Dokument bei jeder Abfrage vollständig neu interpretiert werden muss. Die bekannten JSON-Funktionen bleiben dabei weiterhin relevant, arbeiten aber nun auf einem typisierten Datenträger.
Damit wird SQL Server zu einem System, das sowohl relationale Daten als auch dokumentbasierte Nachrichten unmittelbar verarbeiten kann.
Dokumente prüfen
Bevor ein Dokument ausgewertet wird, das nicht mit dem JSON-Datentyp vorliegt, sollte sichergestellt sein, dass es syntaktisch korrekt ist. Das erspart spätere Fehler.
SELECT ISJSON(@payload);
ISJSON() prüft ausschließlich die JSON-Syntax. Die Funktion stellt sicher, dass das Dokument formal gültig ist, trifft jedoch keine Aussage über Inhalt oder Struktur. In der Praxis wird ISJSON() häufig als Constraint verwendet:
ALTER TABLE IncomingMessages ADD CONSTRAINT CK_IncomingMessages_Json CHECK (ISJSON(Payload) = 1);
Die Datenbank übernimmt damit eine erste technische Validierung, bevor eine fachliche Verarbeitung beginnt.
Einzelne Werte lesen
Der wichtigste Zugriff ist das Extrahieren einzelner Attribute. Hierfür kommt die Funktion JSON_VALUE() zum Einsatz, die über einen JSON-Pfad genau beschreibt, wo der gesuchte Wert steht.
SELECT JSON_VALUE(@payload, '$.orderId'); SELECT JSON_VALUE(@payload, '$.customer.name');
Der zweite Parameter ist dann dieser JSON-Pfad. Das $ steht für das Wurzelelement, danach folgt die Navigation innerhalb des Dokuments. Die Auswertung erfolgt zielgerichtet: SQL Server durchsucht nur den benötigten Abschnitt des Dokuments. JSON_VALUE() liefert grundsätzlich einen skalaren Wert zurück. Intern wird dieser als Zeichenfolge zurückgegeben, weshalb bei numerischen oder zeitlichen Werten eine explizite Typumwandlung sinnvoll ist.
SELECT CAST(JSON_VALUE(@payload, '$.orderId') AS INT);
Durch die explizite Konvertierung erhält der Optimizer eindeutige Typinformationen, was für stabile Abfragepläne entscheidend ist. Ist nicht sichergestellt, ob der Inhalt sich wirklich zu einem Integer umwandeln lässt, kommen auch Alternativen wie TRY_CONVERT() oder TRY_PARSE() in Betracht. Diese liefern NULL, wenn der Wert nicht das gewünschte Format hat, und das kann dann in einen Fallback-Wert umgewandelt werden. Dieser Ansatz ergibt also nur dann Sinn, wenn es auch einen sinnvollen solchen Wert gibt – andernfalls ist ein harter Fehler vielleicht die bessere Wahl.
Zeitangaben in JSON folgen üblicherweise dem ISO-8601-Format. Dieses Format ist kulturunabhängig und kann zuverlässig interpretiert werden. Dadurch lassen sich Zeitbereiche filtern oder Ereignisse chronologisch auswerten.
SELECT CAST(JSON_VALUE(@payload, '$.created') AS DATETIME2);
Filtern nach JSON-Inhalten
JSON-Dokumente werden häufig zunächst vollständig gespeichert, zum Beispiel in Tabellen wie der in dem folgenden Listing:
CREATE TABLE dbo.JsonContent
(
Id INT IDENTITY PRIMARY KEY,
Payload JSON
);
Filternde Abfragen auf diesen Inhalt können nun direkt auf Inhalte des Dokuments zugreifen und können daher wie folgt aussehen:
SELECT * FROM dbo.JsonContent WHERE JSON_VALUE(Payload, '$.customer.name') = 'Meyer';
Die Abfrage ist korrekt, jedoch muss der Server ohne weitere Maßnahmen jedes Dokument untersuchen. Bei größeren Tabellen kann dies zu hohem CPU-Aufwand führen, da der relevante Wert innerhalb des Dokuments gesucht werden muss. Für solche größeren Tabellen bietet der SQL Server 2025 deshalb einen speziellen JSON-Index.
JSON-Index
Mit dem nativen JSON-Datentyp in SQL Server 2025 kommt erstmals ein echter JSON-Index hinzu. Bisher bestand die übliche Strategie darin, einzelne Werte über persistierte berechnete Spalten herauszulösen und darauf klassische B-Tree-Indizes anzulegen. Das funktioniert weiterhin gut, hat aber einen strukturellen Nachteil: Man muss vorher wissen, welche Eigenschaften später abgefragt werden. Bei variablen Dokumenten ist genau das in vielen Fällen nicht möglich.
Der JSON-Index setzt eine Ebene tiefer an. SQL Server zerlegt das Dokument intern in Pfade und Werte und legt darauf eine Suchstruktur an. Der Optimizer kann dadurch gezielt auf einzelne Eigenschaften zugreifen, ohne das komplette Dokument pro Zeile erneut zu parsen. Besonders Abfragen mit JSON_VALUE(), Pfadfiltern oder Existenzprüfungen profitieren davon, weil nicht mehr jede Zeile vollständig untersucht werden muss.
-- Für alle Elemente
CREATE JSON INDEX jsonIndex
ON dbo.JsonContent(Payload);
-- Für Elemente im JSON-Pfad(en), die sich nicht überlappen dürfen
CREATE JSON INDEX jsonIndex
ON dbo.JsonDemo(Payload) FOR ('$.Customer', '$.Employee', '$.Order')
WITH (FILLFACTOR = 80);Aggregationen auf JSON
Da Arrays relational interpretiert werden, können sämtliche SQL-Operationen angewendet werden:
SELECT SUM(qty * price) AS TotalAmount
FROM OPENJSON(@payload, '$.items')
WITH (
sku NVARCHAR(20),
qty INT,
price DECIMAL(10,2)
);
Der SQL Server berechnet dann das Ergebnis direkt aus dem Dokument. Dabei muss nicht mit Schleifen und Ähnlichem gearbeitet werden – dies vereinfacht das Leben in der T-SQL-Welt deutlich.
JSON mit Tabellen verknüpfen
JSON-Inhalte lassen sich mit relationalen Tabellen kombinieren. Dies geschieht mittels der OPENJSON()-Funktion, die eine Tabelle liefert, die zum Beispiel mit einem JOIN zu einer anderen Tabelle verbunden werden kann:
SELECT p.ProductName, j.qty
FROM OPENJSON(@payload, '$.items')
WITH (
sku NVARCHAR(20),
qty INT
) j
JOIN dbo.Products p ON p.Sku = j.sku;
Damit kann zum Beispiel eine eingehende Nachricht unmittelbar gegen Stammdaten geprüft oder erweitert werden.
Teilobjekte lesen
Bisher ging es um einzelne Werte. In der Praxis reicht das selten aus. Sehr häufig muss nicht nur ein Attribut gelesen werden, sondern ein zusammenhängender Teilbereich des Dokuments – etwa ein Adressblock, ein kompletter Kunde oder Metadaten einer Nachricht. Genau dafür existiert JSON_QUERY(). Neben skalaren Werten können auch komplette Teilstrukturen extrahiert werden.
SELECT JSON_QUERY(@payload, '$.customer');
JSON_QUERY() gibt dabei ein gültiges JSON-Fragment zurück, das weiter verarbeitet werden kann. Dies eignet sich insbesondere für Archivierung oder Weiterverarbeitung, wenn ein Teil des Dokuments unverändert benötigt wird. Sinnvoll ist das insbesondere bei:
- Weitergabe an andere Systeme
- Archivierung von Teilinformationen
- mehrstufigen Analysen
- Arbeiten mit verschachtelten Arrays
Die Funktion ist damit weniger eine klassische Lesefunktion, sondern eher ein strukturelles Werkzeug. Sie erlaubt es, Dokumente selektiv zu zerlegen, ohne sie in ihre Einzelteile auflösen zu müssen.
Fazit
Die JSON-Unterstützung in SQL Server erweitert das relationale Modell um die direkte Verarbeitung dokumentbasierter Daten. Einzelne Attribute können gezielt mit JSON_VALUE() gelesen und gefiltert werden, während OPENJSON() komplette Arrays in relationale Ergebnismengen überführt. Ein JSON-Index sorgt dabei auch bei größeren Datenmengen für die entsprechende Performance.
Damit wird die Datenbank nicht nur zum Speicherort für eingehende Informationen, sondern zur ersten Instanz ihrer Analyse: Dokumente können geprüft, interpretiert und in bestehende Datenstrukturen eingeordnet werden, ohne vorherige Transformation außerhalb der Datenbank.