sql >> Database >  >> RDS >> Sqlserver

Hoe geneste JSON in SQL Server te selecteren met OPENJSON

Als u OPENJSON() . gebruikt , maar je probeert te onthouden hoe je een binnenste fragment uit het JSON-document selecteert, lees verder.

De OPENJSON() syntaxis stelt u in staat om JSON-documenten om te zetten in een tabelweergave. U kunt er ook een genest JSON-fragment uit het JSON-document selecteren.

De manier om dit te doen is met paden .

Paden

Een pad bestaat uit het volgende:

  • Een dollarteken ($ ), die het contextitem vertegenwoordigt.
  • Een reeks padstappen. Padstappen kunnen de volgende elementen en operators bevatten:
    • Sleutelnamen. Bijvoorbeeld $.pets en $.pets.dogs . Als de sleutelnaam begint met een dollarteken of speciale tekens zoals spaties bevat, moet deze tussen aanhalingstekens staan ​​(bijvoorbeeld $."my pets" ).
    • Array-elementen. Bijvoorbeeld $.pets.dogs[1] . Array-indexen zijn gebaseerd op nul, dus in dit voorbeeld wordt het tweede element in de array geselecteerd.
    • De puntoperator (. ) geeft een lid van een object aan. Bijvoorbeeld in $.pets.dogs , dogs is lid van pets .

Basisvoorbeeld

Hier is een eenvoudig voorbeeld om te demonstreren.

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)
    );

Resultaat:

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

In dit geval is het tweede argument voor OPENJSON() is '$.pets.dogs' , wat betekent dat we de waarde van de dogs . selecteren sleutel, die zelf een kind is van pets .

Het dollarteken ($ ) staat voor het contextitem.

Merk op dat ik in dit voorbeeld ook de WITH . gebruik clausule om het schema te definiëren. Als ik dat niet zou opnemen, zou in plaats daarvan het standaardschema worden gebruikt.

Zo ziet het eruit met het standaardschema.

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');

Resultaat:

+-------+-------------------------------------------------+--------+
| 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      |
+-------+-------------------------------------------------+--------+

We selecteren dus nog steeds dezelfde geneste JSON, alleen gebruiken we een ander schema.

Het standaardschema retourneert altijd drie kolommen; sleutel , waarde , en typ .

Array-elementen selecteren

Zoals vermeld, kunt u de notatie met vierkante haken gebruiken om een ​​specifiek element in een array te selecteren.

Hier is een voorbeeld.

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)
    );

Resultaat:

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

Aangezien array-indexen op nul zijn gebaseerd, met een waarde van 0 geeft het eerste element in de array terug.

Zo ziet dit voorbeeld eruit bij gebruik van het standaardschema (d.w.z. zonder de WITH clausule).

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]');

Resultaat:

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

Padmodus

Wanneer u paden gebruikt, heeft u de mogelijkheid om de padmodus te declareren.

Padmodus bepaalt wat er gebeurt als een paduitdrukking een fout bevat.

Padmodus kan ofwel lax . zijn of strict .

  • In lax modus, retourneert de functie lege waarden als het pad niet kan worden gevonden. Als u bijvoorbeeld de waarde $.pets.cows . aanvraagt , maar de JSON bevat die sleutel niet, de functie retourneert null, maar geeft geen fout.
  • In strict modus geeft de functie een foutmelding als het pad niet kan worden gevonden.

De standaard padmodus is lax , dus als je het niet aangeeft, lax is gebruikt.

Voorbeeld

Hier is een voorbeeld om te laten zien hoe elke padmodus omgaat met ontbrekende paden.

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');

Resultaat:

(0 rows affected)

Dus de lakse modus gaf geen fouten. Het resulteerde gewoon in nul rijen die werden beïnvloed.

Als we ons eigen schema zouden specificeren, en we selecteerden het juiste subobject, maar we gebruikten een ontbrekend pad om naar een kolomnaam te verwijzen, dan zou het NULL teruggeven in die kolom.

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'
    );

Resultaat:

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

Strikte modus

Dit is wat er gebeurt als we de strikte modus gebruiken.

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');

Resultaat:

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

Zoals verwacht resulteerde dit in een fout.

Dezelfde fout treedt op wanneer we de juiste JSON-sleutel selecteren, maar een kolom toewijzen aan een niet-bestaande sleutel.

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'
    );

Resultaat:

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

Dubbele paden

Als uw JSON-document dubbele paden op hetzelfde nesting-niveau bevat, OPENJSON() kan ze allemaal retourneren.

Dit in tegenstelling tot JSON_VALUE() en JSON_QUERY() , die beide alleen de eerste waarde retourneren die overeenkomt met het pad.

Hier is een voorbeeld van het gebruik van OPENJSON() om dubbele paden te retourneren.

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

Resultaat:

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

Geneste subobjecten

Wanneer u uw eigen schema definieert, kunt u de AS JSON . gebruiken optie om een ​​heel subobject als zijn eigen JSON-document te retourneren.

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
    );

Resultaat:

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

Als we de AS JSON . niet hadden gebruikt optie, zouden we een fout of NULL hebben ontvangen, afhankelijk van of we lax hadden opgegeven of strict modus.

Hier is het in elke modus bij het weglaten van de AS JSON optie.

Losse 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'
    );

Resultaat:

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

Strikte 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'
    );

Resultaat:

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

  1. Java-kruistabel - query voor opgestelde instructie

  2. Percona Live Dublin - Evenementoverzicht en onze sessies

  3. Hoe Mod() werkt in PostgreSQL

  4. Hoe DataFrame naar de postgres-tabel te schrijven?