Die JSON_TABLE-Funktion in MySQL: JSON-Daten relational abfragen
AI generated
InnoDB
SQL
MySQL / JSON
JSON_TABLE: JSON-Daten relational abfragen
Wie sich JSON-Spalten und JSON-Literale in MySQL in virtuelle Tabellen umwandeln lassen

JSON_TABLE ist eine der weniger bekannten, aber praktisch sehr nützlichen Funktionen in MySQL 8: Sie wandelt ein JSON-Dokument, egal ob als Spaltenwert gespeichert oder als Literal in der Query selbst formuliert, in eine reguläre, mit anderen Tabellen joinbare Ergebnismenge um. Statt JSON-Werte umständlich über mehrere JSON_EXTRACT-Aufrufe herauszulösen, liefert JSON_TABLE direkt Zeilen und Spalten, die sich wie jede andere Tabelle behandeln lassen. Dieser Artikel zeigt die grundlegende Funktionsweise, konkrete Anwendungsfälle im Umfeld von Magento-Attributdaten und wo die Performance-Grenzen im Vergleich zu einer echten normalisierten Tabelle liegen.

10 Min. Lesezeit JSON_TABLE JSON-Auswertung

1. Was JSON_TABLE grundsätzlich leistet

JSON_TABLE nimmt als ersten Parameter ein JSON-Dokument entgegen, entweder eine Spalte vom Typ JSON, einen aus einer anderen Spalte extrahierten Teilbereich oder ein direkt in der Query formuliertes JSON-Literal, und wertet es anhand eines beschriebenen Spaltenschemas aus. Das Ergebnis ist eine ganz normale, tabellenartige Ergebnismenge mit benannten Spalten und passenden SQL-Datentypen, die anschließend wie jede andere abgeleitete Tabelle in FROM- oder JOIN-Klauseln verwendet werden kann.

Der entscheidende Unterschied zu JSON_EXTRACT liegt darin, dass JSON_TABLE nicht nur einen einzelnen Wert oder ein einzelnes Teildokument zurückgibt, sondern bei Arrays automatisch mehrere Zeilen erzeugt, eine pro Array-Element. Verschachtelte Strukturen mit mehreren Ebenen lassen sich außerdem über verschachtelte NESTED-PATH-Klauseln direkt auflösen, ohne die Query in mehrere aufwendig zu verknüpfende Teilabfragen aufteilen zu müssen.

2. Grundsyntax an einem einfachen Beispiel

Die einfachste Form von JSON_TABLE arbeitet direkt mit einem JSON-Literal und demonstriert die grundlegende Syntax, ohne dass dafür überhaupt eine Tabelle beteiligt sein muss. Jede Spalte im COLUMNS-Block bekommt einen Namen, einen Zieltyp und einen JSON-Pfad, über den der jeweilige Wert innerhalb des Dokuments gefunden wird.

Für die Basisebene eines Arrays genügt der Pfad '$[*]' in Kombination mit FOR ORDINALITY für eine automatisch generierte Zeilennummer sowie relativen Pfaden wie '$.name' für die einzelnen Felder jedes Array-Elements. Diese Grundstruktur bildet die Basis für alle komplexeren Anwendungsfälle mit echten Spaltenwerten.


SELECT *
FROM JSON_TABLE(
    '[{"sku":"WS-01","qty":12},{"sku":"WS-02","qty":5}]',
    '$[*]'
    COLUMNS (
        row_num FOR ORDINALITY,
        sku     VARCHAR(64) PATH '$.sku',
        qty     INT         PATH '$.qty'
    )
) AS jt;

3. Praxisfall: Magento-Attribut-JSON-Daten relational auswerten

In individuell erweiterten Magento-Datenmodellen landen strukturierte Zusatzinformationen häufig in einer eigenen JSON-Spalte, etwa eine Liste konfigurierbarer Varianten-Metadaten oder eine Sammlung von Lieferantenpreisen pro Staffelmenge, statt für jeden Einzelfall ein eigenes EAV-Attribut anzulegen. Diese Spalten sind für den lesenden Zugriff im Anwendungscode praktisch, entziehen sich aber klassischer SQL-Auswertung, solange sie als reiner JSON-Blob behandelt werden.

Mit JSON_TABLE lässt sich eine solche Spalte direkt im SELECT auf Zeilenebene entfalten und mit anderen Tabellen verknüpfen, etwa um für jede Staffelpreis-Zeile eines Produkts den zugehörigen Katalogpreis oder Lagerbestand gegenüberzustellen. Reports, die vorher eine eigene Anwendungslogik zur JSON-Verarbeitung benötigt hätten, lassen sich dadurch als reines SQL formulieren und direkt in bestehende Reporting-Tools einbinden.


SELECT p.sku, jt.qty_from, jt.price
FROM catalog_product_extra p
JOIN JSON_TABLE(
    p.tier_price_json,
    '$[*]'
    COLUMNS (
        qty_from INT     PATH '$.qty_from',
        price    DECIMAL(10,2) PATH '$.price'
    )
) AS jt
WHERE p.sku = 'WS-01';

4. Verschachtelte JSON-Strukturen mit NESTED PATH auflösen

Sobald ein JSON-Dokument mehrere Verschachtelungsebenen enthält, etwa ein Produkt mit einer Liste von Varianten, die jeweils wiederum eine Liste von Lagerorten mit Bestandsmengen enthalten, reicht ein einzelner PATH-Ausdruck nicht mehr aus. Hier kommt die NESTED-PATH-Klausel innerhalb des COLUMNS-Blocks zum Einsatz, die eine weitere Ebene der Entfaltung direkt in derselben JSON_TABLE-Definition erlaubt.

Das Ergebnis ist eine vollständig flach entfaltete Ergebnismenge, bei der äußere Felder wie die Produkt-SKU automatisch auf jede innere Zeile dupliziert werden, exakt wie bei einem klassischen SQL-Join zwischen zwei normalisierten Tabellen. Ohne NESTED PATH müsste dieselbe Auswertung über mehrere ineinander verschachtelte JSON_TABLE-Aufrufe mit manuellem Join nachgebildet werden, was deutlich unübersichtlicher wird.


SELECT jt.sku, jt.warehouse, jt.stock
FROM JSON_TABLE(
    variant_stock_json,
    '$.variants[*]'
    COLUMNS (
        sku VARCHAR(64) PATH '$.sku',
        NESTED PATH '$.locations[*]'
        COLUMNS (
            warehouse VARCHAR(32) PATH '$.warehouse',
            stock     INT         PATH '$.stock'
        )
    )
) AS jt;

5. Fehlerbehandlung bei fehlenden oder falsch typisierten Werten

JSON-Dokumente aus externen Quellen sind selten so sauber strukturiert wie eine eigene, streng validierte Tabelle, weshalb JSON_TABLE für jede Spalte eine explizite ERROR- und EMPTY-Behandlung erlaubt. Fehlt ein Pfad im Dokument komplett, greift standardmäßig NULL ON EMPTY, während ein Typkonflikt, etwa ein Text an einer als INT deklarierten Stelle, ohne weitere Angabe zu einem harten Fehler in der gesamten Abfrage führt.

Für produktive Auswertungen empfiehlt es sich deshalb, explizit DEFAULT-Werte oder NULL-Verhalten für beide Fälle anzugeben, statt sich auf die impliziten Standardwerte zu verlassen. Gerade bei extern importierten oder von Drittsystemen gelieferten JSON-Daten verhindert diese explizite Behandlung, dass eine einzelne fehlerhafte Zeile den gesamten Report zum Absturz bringt.


COLUMNS (
    sku   VARCHAR(64) PATH '$.sku'  DEFAULT 'unknown' ON EMPTY,
    price DECIMAL(10,2) PATH '$.price'
          DEFAULT '0.00' ON EMPTY DEFAULT '0.00' ON ERROR
)

6. JSON_TABLE im Vergleich zu JSON_EXTRACT und JSON_TABLE-Alternativen

JSON_EXTRACT bleibt die richtige Wahl, wenn lediglich ein einzelner Wert oder ein einzelnes Teildokument aus einer JSON-Spalte gelesen werden soll, etwa als zusätzliche Spalte in einer sonst regulären Abfrage. Sobald aber ein JSON-Array in mehrere SQL-Zeilen aufgelöst werden muss, wird der Code mit JSON_EXTRACT schnell unübersichtlich, weil dafür typischerweise eine rekursive CTE über einen numerischen Index oder eine externe Hilfstabelle mit fortlaufenden Zahlen benötigt wird.

JSON_TABLE übernimmt diese Zeilenerzeugung nativ und lesbar innerhalb einer einzigen Klausel, was den Code sowohl kürzer als auch für andere Entwickler leichter nachvollziehbar macht. Für komplexe, mehrstufige Verschachtelungen bleibt JSON_TABLE dabei klar im Vorteil gegenüber jeder Kombination aus JSON_EXTRACT und manuellem Zeilen-Trick.

7. Performance-Grenzen im Vergleich zu normalisierten Tabellen

So praktisch JSON_TABLE für Auswertungen ist, es bleibt eine Auflösung zur Laufzeit ohne jede Indexunterstützung innerhalb des JSON-Dokuments selbst. Jede Abfrage muss das komplette JSON-Dokument parsen und alle referenzierten Pfade neu auswerten, es gibt keine Möglichkeit, gezielt nur einen Teil eines großen JSON-Arrays zu lesen, wie es ein Index auf einer normalisierten Zeilentabelle erlauben würde.

Bei kleinen bis mittelgroßen Dokumenten und gelegentlichen Auswertungen, etwa in einem täglichen Report, ist dieser Overhead in der Praxis vernachlässigbar. Bei sehr großen Arrays mit tausenden Elementen pro Zeile oder bei Abfragen, die im Sekundentakt in der Anwendung selbst laufen, wird der wiederholte Parsing-Aufwand dagegen schnell zum Engpass, und eine echte normalisierte Kindtabelle mit passendem Fremdschlüssel-Index bleibt die deutlich schnellere Wahl.

8. Wann sich JSON_TABLE lohnt und wann eine echte Tabelle besser ist

JSON_TABLE eignet sich besonders für Ad-hoc-Reporting, Datenmigrationen und Import-Validierungen, bei denen JSON-Daten einmalig oder gelegentlich in eine relationale Form überführt werden müssen, ohne dafür eigens ein neues Tabellenschema aufzusetzen. Auch für flexible, sich häufig ändernde Zusatzattribute, deren Struktur noch nicht endgültig feststeht, ist JSON_TABLE eine pragmatische Zwischenlösung.

Sobald ein Datenmodell stabil geworden ist und regelmäßig, insbesondere lastintensiv im laufenden Anwendungsbetrieb, abgefragt wird, lohnt sich der Umbau in eine echte normalisierte Kindtabelle mit eigenen Indizes fast immer. JSON_TABLE ist dann weiterhin ein nützliches Werkzeug für die einmalige Migration der bestehenden JSON-Daten in dieses neue Schema, nicht aber die dauerhafte Zugriffsschicht für produktive, häufig ausgeführte Abfragen.

9. Praxisbeispiel: JSON-Import-Validierung vor dem Insert

Bei der Anbindung externer Lieferantenfeeds, die Produktdaten als verschachteltes JSON-Dokument liefern, lässt sich JSON_TABLE hervorragend als Validierungsschicht zwischen Rohimport und tatsächlichem Insert in die Zieltabellen einsetzen. Die Rohdaten landen zunächst unverändert in einer Staging-Spalte, anschließend prüft eine JSON_TABLE-Abfrage systematisch auf fehlende Pflichtfelder, unplausible Werte oder doppelte SKUs, bevor überhaupt ein INSERT in die eigentlichen Produkttabellen stattfindet.

Dieser Ansatz verlagert die Validierungslogik konsequent in die Datenbank, statt sie ausschließlich im Anwendungscode zu implementieren, und macht sie dadurch für jeden weiteren Import-Prozess wiederverwendbar, unabhängig davon, welche Anwendung den eigentlichen Import anstößt.

Ansatz Zeilen aus Array Verschachtelung Indexunterstützung Typischer Einsatz
JSON_EXTRACT manuell, umständlich nur einzeln, mehrfach verschachtelt aufwendig keine im Dokument einzelner Wert, Filterbedingung
JSON_TABLE nativ, automatisch direkt über NESTED PATH keine im Dokument Ad-hoc-Reporting, Migration
Generated Column plus Index nicht anwendbar nur flache Felder vollständig indizierbar häufig gefilterter Einzelwert
Normalisierte Kindtabelle regulärer JOIN beliebig über weitere Tabellen vollständig indizierbar produktiver, lastintensiver Zugriff

Mironsoft

Datenbank-Performance, Index-Tuning und Magento-DB-Optimierung

Magento-Shop, der an langsamen Datenbankabfragen leidet?

Wir analysieren MySQL-Datenbanken auf Performance-Bremsen, optimieren Indizes und Abfragen gezielt und richten Backup- und Replikationsstrategien ein, die im Ernstfall wirklich funktionieren.

Performance-Audit

Slow Query Log und Explain-Pläne systematisch auf Engpässe untersuchen.

Index-Optimierung

Indizes gezielt für die tatsächliche Abfragelast des Shops aufbauen.

Backup-Strategie

Zuverlässige Backup- und Restore-Prozesse für produktive Magento-Datenbanken einrichten.

10. Zusammenfassung

JSON_TABLE: Das Wichtigste auf einen Blick

Virtuelle Tabelle aus JSON

JSON_TABLE wandelt JSON-Spalten oder JSON-Literale in eine reguläre, joinbare Ergebnismenge um.

Arrays werden zu Zeilen

Jedes Array-Element erzeugt automatisch eine eigene Zeile, verschachtelte Arrays über NESTED PATH.

Kein Indexersatz

JSON_TABLE liest und parst das komplette Dokument zur Laufzeit, ohne Indexunterstützung innerhalb des JSON.

Ideal für Migration und Reporting

Für stabile, lastintensive Zugriffsmuster bleibt eine echte normalisierte Kindtabelle die schnellere Wahl.

11. FAQ: JSON_TABLE: Das Wichtigste auf einen Blick

1Was ist der Hauptunterschied zwischen JSON_TABLE und JSON_EXTRACT?
JSON_EXTRACT liefert einen einzelnen Wert oder ein Teildokument zurück, JSON_TABLE erzeugt bei Arrays automatisch mehrere Zeilen und liefert damit eine echte, joinbare tabellenartige Ergebnismenge.
2Kann JSON_TABLE mit einem JSON-Literal statt einer Spalte arbeiten?
Ja, der erste Parameter kann sowohl eine JSON-Spalte als auch ein direkt in der Query notiertes JSON-Literal sein, was sich besonders zum Testen der Syntax eignet.
3Wie werden mehrfach verschachtelte JSON-Strukturen ausgewertet?
Über NESTED PATH innerhalb des COLUMNS-Blocks lässt sich eine weitere Verschachtelungsebene direkt in derselben JSON_TABLE-Definition auflösen, ohne mehrere Abfragen manuell zu verknüpfen.
4Was passiert, wenn ein JSON-Pfad in einer Zeile fehlt?
Standardmäßig greift NULL ON EMPTY, es lässt sich aber pro Spalte explizit ein DEFAULT-Wert für fehlende oder fehlerhafte Pfade angeben, was für produktive Abfragen empfehlenswert ist.
5Unterstützt JSON_TABLE Indizes innerhalb des JSON-Dokuments?
Nein, jede Abfrage parst das komplette JSON-Dokument zur Laufzeit neu. Für häufig gefilterte Einzelwerte ist eine Generated Column mit eigenem Index die schnellere Alternative.
6Eignet sich JSON_TABLE für lastintensive, produktive Abfragen?
Eher nicht. Bei sehr großen Dokumenten oder hoher Abfragefrequenz wird der wiederholte Parsing-Aufwand zum Engpass, eine normalisierte Kindtabelle mit Index ist dann die bessere Wahl.
7Wie lässt sich JSON_TABLE mit anderen Tabellen kombinieren?
Die von JSON_TABLE erzeugte Ergebnismenge kann wie jede andere abgeleitete Tabelle in einem regulären JOIN mit anderen Tabellen verknüpft werden, etwa um Preise oder Bestände gegenüberzustellen.
8Für welche Magento-nahen Anwendungsfälle eignet sich JSON_TABLE besonders?
Für die relationale Auswertung von JSON-Attributdaten wie Staffelpreisen oder Varianten-Metadaten in individuell erweiterten Datenmodellen, sowie für Import-Validierung externer Lieferantenfeeds.
9Was passiert bei einem Typkonflikt, etwa Text statt Zahl?
Ohne explizite Fehlerbehandlung führt ein Typkonflikt zu einem harten Fehler der gesamten Abfrage. Mit DEFAULT ON ERROR lässt sich stattdessen ein Ersatzwert definieren.
10Sollte man ein bestehendes Datenmodell dauerhaft auf JSON_TABLE-Abfragen aufbauen?
Für ein stabiles, häufig genutztes Datenmodell empfiehlt sich stattdessen eine echte normalisierte Kindtabelle. JSON_TABLE bleibt dann ein nützliches Werkzeug für die einmalige Migration der bestehenden Daten.