JSON mit Arrays in relationale Strukturen überführen
Von ineinander verschachtelten Listen zu sauberen Spalten und Zeilen – bewährte Techniken in SQL Server, Python und JavaScript.
Problemstellung: JSON mit Arrays
JSON ist das Standardaustauschformat moderner APIs. Oft enthalten die Objekte Arrays – etwa Bestellungen mit mehreren Positionen oder Benutzer mit mehreren Rollen. Will man diese Daten in einer relationalen Datenbank oder in DataFrames analysieren, muss man die Arrays aufbrechen ("flatten") und in eine 1:n‑Beziehung überführen: Eine Zeile pro Array‑Element, bei Wiederholung der übergeordneten Felder.
Beispiel‑JSON:
{
"orderId": 12345,
"customer": "Müller GmbH",
"items": [
{"product": "Notebook", "quantity": 1, "price": 899},
{"product": "Maus", "quantity": 2, "price": 25}
]
}
Gewünschtes relationales Ziel (Tabellenform):
| orderId | customer | product | quantity | price |
|---|---|---|---|---|
| 12345 | Müller GmbH | Notebook | 1 | 899 |
| 12345 | Müller GmbH | Maus | 2 | 25 |
In diesem Artikel zeigen wir, wie Sie das in SQL Server (T-SQL), Python (pandas) und JavaScript (Node.js/Browser) effizient umsetzen.
SQL Server: Mit OPENJSON Arrays aufbrechen
Die Funktion OPENJSON wandelt JSON in relationale Zeilen um. Mit CROSS APPLY wird das Array‑Element pro Zeile expandiert.
DECLARE @json NVARCHAR(MAX) = N'
{
"orderId": 12345,
"customer": "Müller GmbH",
"items": [
{"product": "Notebook", "quantity": 1, "price": 899},
{"product": "Maus", "quantity": 2, "price": 25}
]
}';
SELECT
orderId,
customer,
product,
quantity,
price
FROM OPENJSON(@json)
WITH (
orderId INT '$.orderId',
customer NVARCHAR(100) '$.customer',
items NVARCHAR(MAX) '$.items' AS JSON
) AS header
CROSS APPLY OPENJSON(header.items)
WITH (
product NVARCHAR(50) '$.product',
quantity INT '$.quantity',
price DECIMAL(10,2) '$.price'
);
Erklärung:
- Die äußere
OPENJSONliest die Stammeigenschaften und extrahiert dasitems‑Array als JSON‑String. CROSS APPLY OPENJSON(header.items)erzeugt für jedes Array‑Element eine neue Zeile.- Die innere
WITH‑Klausel definiert die Spalten der Array‑Objekte.
OPENJSON ressourcenintensiv sein. Nutzen Sie dann asynchrone Streaming‑Lösungen oder teilen Sie die Daten vorab auf.
Python: Mit pandas json_normalize und explode
In Python bietet die Bibliothek pandas zwei elegante Wege: json_normalize für geschachtelte JSONs, oder explode nach dem Einlesen.
import pandas as pd
import json
json_data = {
"orderId": 12345,
"customer": "Müller GmbH",
"items": [
{"product": "Notebook", "quantity": 1, "price": 899},
{"product": "Maus", "quantity": 2, "price": 25}
]
}
# Methode 1: json_normalize + record_path
df = pd.json_normalize(json_data, record_path=['items'], meta=['orderId', 'customer'])
print(df)
# Methode 2: Explode (wenn items bereits als Liste von dicts vorliegt)
df_base = pd.DataFrame([json_data]) # Eine Zeile
df_base = df_base.explode('items') # Jedes Array-Element wird neue Zeile
df_base = df_base.drop(columns=['items']).join(pd.DataFrame(df_base.pop('items').tolist()))
print(df_base)
Methode 1 (empfohlen): json_normalize mit record_path für den Array‑Pfad und meta für die zu wiederholenden Felder.
Methode 2: explode erzeugt Zeilen pro Listen‑Element, anschließend wird die Liste von dictionaries in Spalten umgewandelt.
ijson (iterative JSON) oder lesen Sie zeilenweise aus einer Datei, um Speicherüberläufe zu vermeiden.
JavaScript/TypeScript: Array.prototype.flatMap und map
In JavaScript hat man die Wahl zwischen deklarativen Ansätzen mit flatMap oder klassischen for-Schleifen.
const json = {
orderId: 12345,
customer: "Müller GmbH",
items: [
{ product: "Notebook", quantity: 1, price: 899 },
{ product: "Maus", quantity: 2, price: 25 }
]
};
// flatMap: Für jedes Element im Array eine neue Zeile erzeugen
const result = json.items.flatMap(item => ({
orderId: json.orderId,
customer: json.customer,
product: item.product,
quantity: item.quantity,
price: item.price
}));
console.table(result);
Wenn Sie das Ergebnis in eine Tabelle (HTML) oder als CSV exportieren möchten, können Sie die resultierenden Objekte direkt verwenden.
Alternative für verschachtelte Arrays: Rekursive Funktionen oder Bibliotheken wie normalizr.
flatMap Speicher kosten. Verwenden Sie dann einen Generator oder streamen Sie die Ausgabe.
Vergleich der Ansätze
| Merkmal | SQL Server (OPENJSON) | Python (pandas) | JavaScript (flatMap) |
|---|---|---|---|
| Integrationsgrad | Nativ in der DB – keine Extraktion nötig | Perfekt für Data Pipelines (Jupyter, ETL) | Ideal für API‑Antworten im Frontend/Backend |
| Performance bei großen Daten | Gut (optimierte C‑Ebene) | Sehr gut (pandas in C‑basiert) | Akzeptabel, bei > 100k Zeilen jedoch speicherhungrig |
| Komplexität bei tiefen Verschachtelungen | Erfordert mehrere CROSS APPLY | Mit record_path und mehreren Metas gut beherrschbar | Rekursive Funktion nötig |
| Lernkurve | Mittel (OPENJSON‑Syntax) | Gering (pandas API) | Gering (Array‑Methoden) |
Empfehlung: Wählen Sie die Methode, die in Ihrer bestehenden Umgebung am natürlichsten ist. Wenn Sie bereits eine Datenbank nutzen, ist OPENJSON ideal; für Data‑Analyse ist pandas erste Wahl; für Web‑Anwendungen bietet JavaScript die direkteste Integration.
Best Practices & Fallstricke
✅ Do
- JSON immer auf korrekte Syntax prüfen (Validierung).
- Für SQL Server:
WITH‑Schema mit expliziten Typen angeben (vermeidet Laufzeitkonvertierungen). - In Python: Bei fehlenden Werten
errors='ignore'beijson_normalizenutzen. - Große JSONs in Blöcken verarbeiten (Streaming).
- Indizierung auf die extrahierten Felder in der Datenbank für spätere Abfragen.
❌ Don't
- Keine manuellen String‑Parsing‑Skripte schreiben – nutzen Sie native Funktionen.
- Nicht jedes Array als separate Tabelle ohne Fremdschlüssel ablegen – sonst verlieren Sie die Beziehung.
- Keine unnötigen
APPLY‑Verschachtelungen bei flachen JSONs. - Im Frontend nicht mehrere Megabyte JSON im Haupt‑Thread parsen (→ Web Worker nutzen).
Erweiterte Szenarien
Häufig findet man JSON wie:
{
"orderId": 123,
"items": [
{"product": "PC", "options": [{"name": "RAM", "value": "16GB"}, {"name": "SSD", "value": "512GB"}]}
]
}
SQL Server: Mehrfaches CROSS APPLY – erst über items, dann über options. Mit OPENJSON rekursiv.
SELECT o.orderId, i.product, opt.name, opt.value
FROM OPENJSON(@json) WITH (orderId INT '$.orderId', items NVARCHAR(MAX) '$.items' AS JSON) o
CROSS APPLY OPENJSON(o.items) WITH (product NVARCHAR(50) '$.product', options NVARCHAR(MAX) '$.options' AS JSON) i
CROSS APPLY OPENJSON(i.options) WITH (name NVARCHAR(50) '$.name', value NVARCHAR(50) '$.value') opt;
Python: Einfach json_normalize mit rekursivem record_path (mehrfach) oder manuelles Exploding.
JavaScript: Verschachtelte flatMap oder reduce.
Fazit
JSON mit Arrays zu normalisieren ist eine Kernaufgabe im modernen Daten‑Engineering. Die Techniken sind dank nativer Funktionen in SQL Server, pandas und modernem JavaScript gut beherrschbar.
- Im SQL Server verwendet man
OPENJSON+CROSS APPLY– schnell und direkt in der Datenbank. - In Python ist
pandas.json_normalizeder Königsweg für DataFrames. - In JavaScript liefern
flatMapundmapeine elegante, typsichere Lösung.
Egal für welche Sprache Sie sich entscheiden: Das Aufbrechen von Arrays reduziert die JSON‑Komplexität und macht die Daten für Analysen, Berichte und effiziente Abfragen nutzbar.