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

So wählen Sie verschachteltes JSON in SQL Server mit OPENJSON aus

Wenn Sie OPENJSON() verwenden , aber Sie versuchen sich daran zu erinnern, wie Sie ein inneres Fragment aus dem JSON-Dokument auswählen, lesen Sie weiter.

Der OPENJSON() -Syntax können Sie JSON-Dokumente in eine tabellarische Ansicht konvertieren. Außerdem können Sie ein verschachteltes JSON-Fragment aus dem JSON-Dokument auswählen.

Der Weg, dies zu tun, ist mit Pfads .

Pfade

Ein Pfad besteht aus Folgendem:

  • Ein Dollarzeichen ($ ), das das Kontextelement darstellt.
  • Eine Reihe von Pfadschritten. Pfadschritte können die folgenden Elemente und Operatoren enthalten:
    • Schlüsselnamen. Beispiel:$.pets und $.pets.dogs . Wenn der Schlüsselname mit einem Dollarzeichen beginnt oder Sonderzeichen wie Leerzeichen enthält, muss er in Anführungszeichen gesetzt werden (z. B. $."my pets"). ).
    • Array-Elemente. Beispiel:$.pets.dogs[1] . Array-Indizes sind nullbasiert, daher wird in diesem Beispiel das zweite Element im Array ausgewählt.
    • Der Punktoperator (. ) gibt einen Member eines Objekts an. Zum Beispiel in $.pets.dogs , dogs ist Mitglied von pets .

Einfaches Beispiel

Hier ist ein einfaches Beispiel zur Veranschaulichung.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs')
WITH  (
        [id]    int,  
        [name]  varchar(60), 
        [sex]   varchar(6)
    );

Ergebnis:

+------+--------+--------+
| id   | name   | sex    |
|------+--------+--------|
| 1    | Fetch  | Male   |
| 2    | Fluffy | Male   |
| 3    | Wag    | Female |
+------+--------+--------+

In diesem Fall das zweite Argument für OPENJSON() ist '$.pets.dogs' , was bedeutet, dass wir den Wert von dogs auswählen Schlüssel, der selbst ein Kind von pets ist .

Das Dollarzeichen ($ ) stellt das Kontextelement dar.

Beachten Sie, dass ich in diesem Beispiel auch den WITH verwende -Klausel, um das Schema zu definieren. Wenn ich das nicht einbeziehen würde, würde stattdessen das Standardschema verwendet werden.

So sieht es mit dem Standardschema aus.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs');

Ergebnis:

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

Wir wählen also immer noch dasselbe verschachtelte JSON aus, nur verwenden wir ein anderes Schema.

Das Standardschema gibt immer drei Spalten zurück; Schlüssel , Wert , und tippen .

Array-Elemente auswählen

Wie bereits erwähnt, können Sie die Notation mit eckigen Klammern verwenden, um ein bestimmtes Element in einem Array auszuwählen.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs[0]')
WITH  (
        [id]    int,  
        [name]  varchar(60), 
        [sex]   varchar(6)
    );

Ergebnis:

+------+--------+-------+
| id   | name   | sex   |
|------+--------+-------|
| 1    | Fetch  | Male  |
+------+--------+-------+

Da Array-Indizes nullbasiert sind und einen Wert von 0 angeben gibt das erste Element im Array zurück.

So sieht dieses Beispiel aus, wenn das Standardschema verwendet wird (d. h. ohne WITH Klausel).

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs[0]');

Ergebnis:

+-------+---------+--------+
| key   | value   | type   |
|-------+---------+--------|
| id    | 1       | 2      |
| name  | Fetch   | 1      |
| sex   | Male    | 1      |
+-------+---------+--------+

Pfadmodus

Bei der Verwendung von Pfaden haben Sie die Möglichkeit, den Pfadmodus zu deklarieren.

Der Pfadmodus bestimmt, was passiert, wenn ein Pfadausdruck einen Fehler enthält.

Der Pfadmodus kann entweder lax sein oder strict .

  • In lax Modus gibt die Funktion leere Werte zurück, wenn der Pfad nicht gefunden werden kann. Wenn Sie beispielsweise den Wert $.pets.cows anfordern , aber der JSON enthält diesen Schlüssel nicht, gibt die Funktion null zurück, löst aber keinen Fehler aus.
  • In strict Modus, löst die Funktion einen Fehler aus, wenn der Pfad nicht gefunden werden kann.

Der Standardpfadmodus ist lax , wenn Sie es also nicht deklarieren, lax wird genutzt.

Beispiel

Hier ist ein Beispiel, um zu demonstrieren, wie jeder Pfadmodus mit fehlenden Pfaden umgeht.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, 'lax $.pets.cows');

Ergebnis:

(0 rows affected)

Der laxe Modus hat also keine Fehler ausgegeben. Es führte einfach dazu, dass null Zeilen betroffen waren.

Wenn wir unser eigenes Schema angegeben und das richtige Unterobjekt ausgewählt, aber einen fehlenden Pfad zur Zuordnung zu einem Spaltennamen verwendet hätten, würde es NULL zurückgeben in dieser Spalte.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}'

SELECT *
FROM OPENJSON(@json, 'lax $.pets.dogs')
WITH  (
        [id]    int         'lax $.id',  
        [name]  varchar(60) 'lax $.name', 
        [color]   varchar(6)  'lax $.color'
    );

Ergebnis:

+------+--------+---------+
| id   | name   | color   |
|------+--------+---------|
| 1    | Fetch  | NULL    |
| 2    | Fluffy | NULL    |
| 3    | Wag    | NULL    |
+------+--------+---------+

Strikter Modus

Folgendes passiert, wenn wir den strikten Modus verwenden.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, 'strict $.pets.cows');

Ergebnis:

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

Wie erwartet führte dies zu einem Fehler.

Derselbe Fehler tritt auf, wenn wir den richtigen JSON-Schlüssel auswählen, aber eine Spalte einem nicht vorhandenen Schlüssel zuordnen.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, 'strict $.pets.dogs')
WITH  (
        [id]    int         'strict $.id',  
        [name]  varchar(60) 'strict $.name', 
        [color]   varchar(6)  'strict $.color'
    );

Ergebnis:

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

Doppelte Pfade

Wenn Ihr JSON-Dokument doppelte Pfade auf derselben Verschachtelungsebene enthält, OPENJSON() kann sie alle zurückgeben.

Dies steht im Gegensatz zu JSON_VALUE() und JSON_QUERY() , die beide nur den ersten Wert zurückgeben, der mit dem Pfad übereinstimmt.

Hier ist ein Beispiel für die Verwendung von OPENJSON() um doppelte Pfade zurückzugeben.

DECLARE @json NVARCHAR(4000) = N'{
    "dog": {
            "names": {
                "name": "Fetch", 
                "name": "Good Dog"
            }
        }
    }';
SELECT * FROM OPENJSON(@json, '$.dog.names');

Ergebnis:

+-------+----------+--------+
| key   | value    | type   |
|-------+----------+--------|
| name  | Fetch    | 1      |
| name  | Good Dog | 1      |
+-------+----------+--------+

Verschachtelte Unterobjekte

Wenn Sie Ihr eigenes Schema definieren, können Sie den AS JSON verwenden Option, ein ganzes Unterobjekt als eigenes JSON-Dokument zurückzugeben.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets')
WITH  (
        [dogs]  nvarchar(max) '$.dogs' AS JSON
    );

Ergebnis:

+--------+
| dogs   |
|--------|
| [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]        |
+--------+

Wenn wir nicht den AS JSON verwendet hätten -Option hätten wir einen Fehler oder NULL erhalten, je nachdem, ob wir lax angegeben haben oder strict Modus.

Hier ist es in jedem Modus, wenn der AS JSON weggelassen wird Option.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets')
WITH  (
        [dogs]  nvarchar(max) 'lax $.dogs'
    );

Ergebnis:

+--------+
| dogs   |
|--------|
| NULL   |
+--------+

Strikter 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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets')
WITH  (
        [dogs]  nvarchar(max) 'strict $.dogs'
    );

Ergebnis:

Msg 13624, Level 16, State 1, Line 16
Object or array cannot be found in the specified JSON path.