Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Einführung in OPENJSON mit Beispielen (SQL Server)

SQL Server verfügt über eine Tabellenwertfunktion namens OPENJSON() die eine relationale Ansicht von JSON-Daten erstellt.

Wenn Sie es aufrufen, übergeben Sie ein JSON-Dokument als Argument und OPENJSON() analysiert es dann und gibt die Objekte und Eigenschaften des JSON-Dokuments in einem tabellarischen Format zurück – als Zeilen und Spalten.

Beispiel

Hier ist ein einfaches Beispiel zur Veranschaulichung.

SELECT * FROM OPENJSON('["Cat","Dog","Bird"]');

Ergebnis:

+-------+---------+--------+
| key   | value   | type   |
|-------+---------+--------|
| 0     | Cat     | 1      |
| 1     | Dog     | 1      |
| 2     | Bird    | 1      |
+-------+---------+--------+

Standardmäßig OPENJSON() gibt eine Tabelle mit drei Spalten zurück; Schlüssel , Wert , und tippen .

Sie haben auch die Möglichkeit, Ihr eigenes Schema anzugeben (d. h. Sie können Ihre eigenen Spalten definieren). In meinem einfachen Beispiel habe ich das Standardschema verwendet, und daher wurden die drei Standardspalten zurückgegeben.

Diese Spalten sind wie folgt definiert:

Spalte Beschreibung
Schlüssel Enthält den Namen der angegebenen Eigenschaft oder den Index des Elements im angegebenen Array. Dies ist ein nvarchar(4000) -Wert, und die Spalte hat eine BIN2-Kollatierung.
Wert Enthält den Wert der Eigenschaft. Dies ist ein nvarchar(max) -Wert, und die Spalte erbt ihre Sortierung vom bereitgestellten JSON.
Typ Enthält den JSON-Typ des Werts. Dies wird als int dargestellt Wert (von 0 bis 5 ). Diese Spalte wird nur zurückgegeben, wenn Sie das Standardschema verwenden.

Standardtypen

In der Welt von JSON gibt es sechs Datentypen. Dies sind String , Nummer , wahr/falsch (boolesch), Null , Objekt und Array .

Wenn Sie JSON durch OPENJSON() parsen unter Verwendung des Standardschemas OPENJSON() ermittelt, was der JSON-Typ ist, und füllt dann den Typ Spalte mit einem int Wert, der diesen Typ darstellt.

Der int Der Wert kann daher zwischen 0 liegen bis 5 . Jeder int value stellt einen JSON-Typ dar, wie in der folgenden Tabelle beschrieben.

Wert in der Spalte „Typ“ JSON-Datentyp
0 Null
1 Zeichenfolge
2 Nummer
3 wahr/falsch
4 Array
5 Objekt

Das folgende Beispiel gibt alle sechs dieser JSON-Typen zurück.

SELECT * FROM OPENJSON('{"name" : null}');
SELECT * FROM OPENJSON('["Cat","Dog","Bird"]');
SELECT * FROM OPENJSON('[1,2,3]');
SELECT * FROM OPENJSON('[true,false]');
SELECT * FROM OPENJSON('{"cats":[{ "id":1, "name":"Fluffy"},{ "id":2, "name":"Scratch"}]}');
SELECT * FROM OPENJSON('[{"A":1,"B":0,"C":1}]');

Ergebnis:

+-------+---------+--------+
| key   | value   | type   |
|-------+---------+--------|
| name  | NULL    | 0      |
+-------+---------+--------+
(1 row affected)
+-------+---------+--------+
| key   | value   | type   |
|-------+---------+--------|
| 0     | Cat     | 1      |
| 1     | Dog     | 1      |
| 2     | Bird    | 1      |
+-------+---------+--------+
(3 rows affected)
+-------+---------+--------+
| key   | value   | type   |
|-------+---------+--------|
| 0     | 1       | 2      |
| 1     | 2       | 2      |
| 2     | 3       | 2      |
+-------+---------+--------+
(3 rows affected)
+-------+---------+--------+
| key   | value   | type   |
|-------+---------+--------|
| 0     | true    | 3      |
| 1     | false   | 3      |
+-------+---------+--------+
(2 rows affected)
+-------+----------------------------------------------------------+--------+
| key   | value                                                    | type   |
|-------+----------------------------------------------------------+--------|
| cats  | [{ "id":1, "name":"Fluffy"},{ "id":2, "name":"Scratch"}] | 4      |
+-------+----------------------------------------------------------+--------+
(1 row affected)
+-------+---------------------+--------+
| key   | value               | type   |
|-------+---------------------+--------|
| 0     | {"A":1,"B":0,"C":1} | 5      |
+-------+---------------------+--------+
(1 row affected)

Verschachteltes JSON zurückgeben

Sie können ein verschachteltes Objekt oder Array zurückgeben, indem Sie seinen Pfad als optionales zweites Argument angeben.

Mit anderen Worten, Sie müssen nicht das gesamte JSON-Dokument parsen – Sie können auch nur den Teil parsen, der Sie interessiert.

Hier ist ein Beispiel.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';
SELECT * FROM OPENJSON(@json, '$.pets.cats');

Ergebnis:

+-------+------------------------------------------------------+--------+
| key   | value                                                | type   |
|-------+------------------------------------------------------+--------|
| 0     | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    | 5      |
| 1     | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } | 5      |
| 2     | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     | 5      |
+-------+------------------------------------------------------+--------+

In diesem Fall habe ich einen Pfad von $.pets.cats angegeben , was nur den Wert von cats ergab zurückgegeben wird. Der Wert von Katzen ist ein Array, also wurde das ganze Array zurückgegeben.

Um nur eine Katze (d. h. ein Array-Element) zurückzugeben, können wir die Syntax mit eckigen Klammern zum Zurückgeben von Array-Werten verwenden (wie hier $.pets.cats[1] ).

Hier ist das gleiche Beispiel, das so modifiziert wurde, dass es nur ein Array-Element zurückgibt:

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';
SELECT * FROM OPENJSON(@json, '$.pets.cats[1]');

Ergebnis:

+-------+-----------+--------+
| key   | value     | type   |
|-------+-----------+--------|
| id    | 2         | 2      |
| name  | Long Tail | 1      |
| sex   | Female    | 1      |
+-------+-----------+--------+

JSON-Array-Indizes sind nullbasiert, daher hat dieses Beispiel den zweiten Array-Wert zurückgegeben (weil ich $.pets.cats[1] angegeben habe ).

Wenn ich $.pets.cats[0] angegeben hätte , wäre der erste Wert zurückgegeben worden (d. h. die Katze namens „Fluffy“).

Definiere ein Schema

Wie bereits erwähnt, können Sie Ihr eigenes Schema angeben (d. h. Ihre eigenen Spalten und Typen definieren).

Hier ist ein Beispiel dafür.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT * FROM OPENJSON(@json, '$.pets.cats')
WITH  (
        [Cat Id]    int             '$.id',  
        [Cat Name]  varchar(60)     '$.name', 
        [Sex]       varchar(6)      '$.sex', 
        [Cats]      nvarchar(max)   '$' AS JSON   
    );

Ergebnis:

+----------+------------+--------+------------------------------------------------------+
| Cat Id   | Cat Name   | Sex    | Cats                                                 |
|----------+------------+--------+------------------------------------------------------|
| 1        | Fluffy     | Female | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    |
| 2        | Long Tail  | Female | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } |
| 3        | Scratch    | Male   | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     |
+----------+------------+--------+------------------------------------------------------+

Wir können sehen, dass die Spaltennamen diejenigen widerspiegeln, die ich in WITH angegeben habe Klausel. In dieser Klausel habe ich jeden JSON-Schlüssel meinen eigenen bevorzugten Spaltennamen zugeordnet. Ich habe auch den SQL Server-Datentyp angegeben, den ich für jede Spalte haben möchte.

Ich habe auch AS JSON verwendet in der letzten Spalte, um diese Spalte als JSON-Fragment zurückzugeben. Wenn Sie AS JSON verwenden, muss der Datentyp nvarchar(max) sein .

Überprüfen Sie die Datentypen

Wir können die folgende Abfrage verwenden, um die Datentypen jeder Spalte zu überprüfen.

Diese Abfrage verwendet das sys.dm_exec_describe_first_result_set systemdynamische Verwaltungsansicht, die Metadaten über die erste Ergebnismenge einer Abfrage zurückgibt.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT 
    name,
    system_type_name
FROM sys.dm_exec_describe_first_result_set(
    'SELECT * FROM OPENJSON(@json, ''$.pets.cats'') WITH  (
        [Cat Id]    int             ''$.id'',  
        [Cat Name]  varchar(60)     ''$.name'', 
        [Sex]       varchar(6)      ''$.sex'', 
        [Cats]      nvarchar(max)   ''$'' AS JSON 
    )',
    null,
    0
);

Ergebnis:

+----------+--------------------+
| name     | system_type_name   |
|----------+--------------------|
| Cat Id   | int                |
| Cat Name | varchar(60)        |
| Sex      | varchar(6)         |
| Cats     | nvarchar(max)      |
+----------+--------------------+

Wir können sehen, dass sie perfekt zu meinem Schema passen.

Beachten Sie, dass die Taste , Wert , und tippen Spalten sind nicht verfügbar, wenn Sie Ihr eigenes Schema definieren. Diese Spalten sind nur verfügbar, wenn das Standardschema verwendet wird.

Fügen Sie das geparste JSON in eine Tabelle ein

Jetzt denken Sie vielleicht, dass wir unser geparstes JSON einfach in eine Datenbanktabelle einfügen könnten.

Und Sie haben recht.

Wir haben es bereits mit Spalten und Zeilen vorbereitet, und wir haben sogar die Spalten benannt und ihnen Datentypen gegeben.

Jetzt ist es an der Zeit, es in eine Tabelle einzufügen.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT * INTO JsonCats
FROM OPENJSON(@json, '$.pets.cats')
WITH  (
        [Cat Id]    int             '$.id',  
        [Cat Name]  varchar(60)     '$.name', 
        [Sex]       varchar(6)      '$.sex', 
        [Cats]      nvarchar(max)   '$' AS JSON   
    );

Ich habe lediglich INTO JsonCats hinzugefügt zu meiner Abfrage, um eine Tabelle namens JsonCats zu erstellen und fügen Sie die Ergebnisse der Abfrage ein.

Lassen Sie uns nun den Inhalt dieser Tabelle auswählen.

SELECT * FROM JsonCats;

Ergebnis:

+----------+------------+--------+------------------------------------------------------+
| Cat Id   | Cat Name   | Sex    | Cats                                                 |
|----------+------------+--------+------------------------------------------------------|
| 1        | Fluffy     | Female | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    |
| 2        | Long Tail  | Female | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } |
| 3        | Scratch    | Male   | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     |
+----------+------------+--------+------------------------------------------------------+

Der Inhalt ist genau so, wie wir ihn im vorherigen Beispiel gesehen haben.

Und um ganz sicherzugehen, können wir jetzt die sys.column verwenden Systemkatalogansicht überprüfen Sie die Spaltennamen und -typen der Tabelle.

SELECT
    name AS [Column],
    TYPE_NAME(system_type_id) AS [Type],
    max_length
FROM sys.columns 
WHERE OBJECT_ID('JsonCats') = object_id;

Ergebnis:

+----------+----------+--------------+
| Column   | Type     | max_length   |
|----------+----------+--------------|
| Cat Id   | int      | 4            |
| Cat Name | varchar  | 60           |
| Sex      | varchar  | 6            |
| Cats     | nvarchar | -1           |
+----------+----------+--------------+

Wieder genau so, wie wir es angegeben hatten.

Beachten Sie, dass sys.columns gibt immer eine max_length zurück von -1 wenn der Datentyp der Spalte varchar(max) ist , nvarchar(max) , varbinary(max) , oder xml . Wir haben nvarchar(max) angegeben und damit der Wert von -1 ist genau wie erwartet.

Pfadmodus:Locker vs. streng

Der im zweiten Argument oder im WITH angegebene Pfad Klausel kann (optional) mit lax beginnen oder strict Schlüsselwort.

  • In lax Modus, OPENJSON() löst keinen Fehler aus, wenn das Objekt oder der Wert im angegebenen Pfad nicht gefunden werden kann. Wenn der Pfad nicht gefunden werden kann, OPENJSON() gibt entweder eine leere Ergebnismenge oder einen NULL zurück Wert.
  • In strict Modus, OPENJSON() gibt einen Fehler zurück, wenn der Pfad nicht gefunden werden kann.

Der Standardwert ist lax , wenn Sie also keinen Pfadmodus angeben, lax Modus verwendet.

Hier sind einige Beispiele, um zu demonstrieren, was mit jedem Modus passiert, wenn der Pfad nicht gefunden werden kann.

Zweites Argument

In den nächsten beiden Beispielen gebe ich beim Aufruf von OPENJSON() im zweiten Argument einen nicht vorhandenen Pfad an . Das erste Beispiel zeigt, was passiert, wenn der laxe Modus verwendet wird, das zweite Beispiel zeigt, was passiert, wenn der strikte Modus verwendet wird.

Lax-Modus

Folgendes passiert in lax Modus, wenn der Pfad nicht gefunden werden kann.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';
SELECT * FROM OPENJSON(@json, 'lax $.pets.cows');

Ergebnis:

(0 rows affected)

Kein Fehler. Es wurden nur keine Ergebnisse zurückgegeben.

Strikter Modus

Hier ist es jetzt in strict Modus.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}'
SELECT * FROM OPENJSON(@json, 'strict $.pets.cows');

Ergebnis:

Msg 13608, Level 16, State 3, Line 15
Property cannot be found on the specified JSON path.

Wie erwartet führte der strikte Modus zu einem Fehler.

In der WITH-Klausel

In den nächsten beiden Beispielen testen wir erneut den laxen Modus im Vergleich zum strikten Modus, außer dass wir ihn dieses Mal in WITH angeben -Klausel beim Definieren des Schemas.

Lax-Modus

Folgendes passiert in lax Modus.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.cats')
WITH  (
        [Cat Id]    int             '$.id',  
        [Cat Name]  varchar(60)     '$.name', 
        [Born]      date            'lax $.born', 
        [Cats]      nvarchar(max)   '$' AS JSON   
    );

Ergebnis:

+----------+------------+--------+------------------------------------------------------+
| Cat Id   | Cat Name   | Born   | Cats                                                 |
|----------+------------+--------+------------------------------------------------------|
| 1        | Fluffy     | NULL   | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    |
| 2        | Long Tail  | NULL   | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } |
| 3        | Scratch    | NULL   | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     |
+----------+------------+--------+------------------------------------------------------+

In diesem Fall verwende ich 'lax $.born' weil ich versuche, auf einen Schlüssel namens born zu verweisen , aber ein solcher Schlüssel existiert nicht im JSON.

Diesmal ergibt die Spalte, die nicht gefunden werden kann, einen NULL Wert.

Strikter Modus

Hier ist es jetzt in strict Modus.

DECLARE @json NVARCHAR(4000) = N'{ 
    "pets" : {
            "cats" : [
            { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
            { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
            { "id" : 3, "name" : "Scratch", "sex" : "Male" }
        ],
            "dogs" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.cats')
WITH  (
        [Cat Id]    int             '$.id',  
        [Cat Name]  varchar(60)     '$.name', 
        [Born]      date            'strict $.born', 
        [Cats]      nvarchar(max)   '$' AS JSON   
    );

Ergebnis:

Msg 13608, Level 16, State 6, Line 16
Property cannot be found on the specified JSON path.

Dieses Mal habe ich 'strict $.born' verwendet .

Wie erwartet führte der strikte Modus zu einem Fehler.

Kompatibilitätsgrad

Der OPENJSON() Funktion ist nur unter Kompatibilitätsstufe 130 oder höher verfügbar.

Wenn Ihr Datenbankkompatibilitätsgrad niedriger als 130 ist, kann SQL Server OPENJSON() nicht finden und ausführen , und Sie erhalten eine Fehlermeldung.

Sie können Ihren Datenbank-Kompatibilitätsgrad über sys.databases überprüfen Katalogansicht.

Sie können den Kompatibilitätsgrad wie folgt ändern:

ALTER DATABASE DatabaseName 
SET COMPATIBILITY_LEVEL = 150;

Neu bei JSON?

Wenn Sie mit JSON nicht so vertraut sind, sehen Sie sich mein JSON-Tutorial bei Quackit an.