sql >> Database >  >> RDS >> Sqlserver

Inleiding tot OPENJSON met voorbeelden (SQL Server)

SQL Server heeft een functie met tabelwaarde genaamd OPENJSON() die een relationele weergave van JSON-gegevens creëert.

Als je het aanroept, geef je een JSON-document door als argument, en OPENJSON() parseert het vervolgens en retourneert de objecten en eigenschappen van het JSON-document in tabelvorm - als rijen en kolommen.

Voorbeeld

Hier is een eenvoudig voorbeeld om te demonstreren.

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

Resultaat:

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

Standaard OPENJSON() geeft een tabel met drie kolommen terug; sleutel , waarde , en typ .

U heeft ook de mogelijkheid om uw eigen schema op te geven (wat betekent dat u uw eigen kolommen kunt definiëren). In mijn eenvoudige voorbeeld gebruikte ik het standaardschema, en dus werden de drie standaardkolommen geretourneerd.

Deze kolommen zijn als volgt gedefinieerd:

Kolom Beschrijving
sleutel Bevat de naam van de opgegeven eigenschap of de index van het element in de opgegeven array. Dit is een nvarchar(4000) waarde, en de kolom heeft een BIN2-sortering.
waarde Bevat de waarde van het onroerend goed. Dit is een nvarchar(max) waarde, en de kolom erft zijn sortering van de verstrekte JSON.
type Bevat het JSON-type van de waarde. Dit wordt weergegeven als een int waarde (van 0 tot 5 ). Deze kolom wordt alleen geretourneerd wanneer u het standaardschema gebruikt.

Standaardtypen

In de wereld van JSON zijn er zes gegevenstypen. Dit zijn string , nummer , waar/onwaar (booleaans), null , voorwerp , en array .

Wanneer u een JSON parseert via OPENJSON() met behulp van het standaardschema, OPENJSON() berekent wat het JSON-type is en vult vervolgens het type kolom met een int waarde die dat type vertegenwoordigt.

De int waarde kan daarom variëren van 0 tot 5 . Elke int waarde vertegenwoordigt een JSON-type zoals beschreven in de volgende tabel.

Waarde in de kolom "type" JSON-gegevenstype
0 null
1 tekenreeks
2 nummer
3 waar/onwaar
4 matrix
5 voorwerp

Het volgende voorbeeld retourneert alle zes van deze JSON-typen.

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

Resultaat:

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

Retourneer geneste JSON

U kunt een genest object of array retourneren door het pad op te geven als een optioneel tweede argument.

Met andere woorden, u hoeft niet het hele JSON-document te ontleden - u kunt ervoor kiezen om alleen het deel te ontleden waarin u geïnteresseerd bent.

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" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';
SELECT * FROM OPENJSON(@json, '$.pets.cats');

Resultaat:

+-------+------------------------------------------------------+--------+
| 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 dit geval heb ik een pad gespecificeerd van $.pets.cats , wat resulteerde in alleen de waarde van katten wordt teruggestuurd. De waarde van katten is een array, dus de hele array is geretourneerd.

Om slechts één kat te retourneren (d.w.z. één array-element), kunnen we de syntaxis van vierkante haakjes gebruiken voor het retourneren van arraywaarden (zoals deze $.pets.cats[1] ).

Hier is hetzelfde voorbeeld aangepast om slechts één array-element 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" : [
            { "name" : "Fetch", "sex" : "Male" },
            { "name" : "Fluffy", "sex" : "Male" },
            { "name" : "Wag", "sex" : "Female" }
        ]
    }
}';
SELECT * FROM OPENJSON(@json, '$.pets.cats[1]');

Resultaat:

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

JSON-array-indexen zijn gebaseerd op nul, dus dit voorbeeld retourneerde de tweede arraywaarde (omdat ik $.pets.cats[1] heb opgegeven ).

Als ik $.pets.cats[0] . had opgegeven , zou de eerste waarde zijn geretourneerd (d.w.z. de kat genaamd "Fluffy").

Een schema definiëren

Zoals vermeld, kunt u uw eigen schema specificeren (d.w.z. uw eigen kolommen en typen definiëren).

Hier is een voorbeeld om dat te doen.

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

Resultaat:

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

We kunnen zien dat de kolomnamen de namen weerspiegelen die ik heb gespecificeerd in de WITH clausule. In die clausule heb ik elke JSON-sleutel toegewezen aan mijn eigen voorkeurskolomnamen. Ik heb ook het SQL Server-gegevenstype gespecificeerd dat ik voor elke kolom wil.

Ik gebruikte ook AS JSON op de laatste kolom om die kolom als een JSON-fragment te retourneren. Als u AS JSON gebruikt, moet het gegevenstype nvarchar(max) . zijn .

Controleer de gegevenstypen

We kunnen de volgende query gebruiken om de gegevenstypen van elke kolom te verifiëren.

Deze query gebruikt de sys.dm_exec_describe_first_result_set dynamische systeembeheerweergave, die metagegevens retourneert over de eerste resultatenset van een zoekopdracht.

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

Resultaat:

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

We kunnen zien dat ze perfect overeenkomen met mijn schema.

Merk op dat de toets , waarde , en typ kolommen zijn niet beschikbaar wanneer u uw eigen schema definieert. Die kolommen zijn alleen beschikbaar bij gebruik van het standaardschema.

Voeg de geparseerde JSON in een tabel in

Inmiddels denk je misschien dat we onze geparseerde JSON gemakkelijk in een databasetabel kunnen invoegen.

En je zou gelijk hebben.

We hebben het al voorbereid met kolommen en rijen, en we hebben de kolommen zelfs een naam gegeven en gegevenstypen gegeven.

Nu is het tijd om het in een tabel in te voegen.

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

Het enige wat ik deed was INTO JsonCats . toevoegen op mijn vraag, om een ​​tabel te maken met de naam JsonCats en voeg de resultaten van de zoekopdracht erin toe.

Laten we nu de inhoud van die tabel selecteren.

SELECT * FROM JsonCats;

Resultaat:

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

De inhoud is precies zoals we ze in het eerdere voorbeeld zagen.

En om absoluut zeker te zijn, kunnen we nu de sys.column . gebruiken systeemcatalogusweergave controleer de kolomnamen en typen van de tabel.

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

Resultaat:

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

Nogmaals, precies hoe we het hadden gespecificeerd.

Merk op dat sys.columns retourneert altijd een max_length van -1 wanneer het kolomgegevenstype varchar(max) . is , nvarchar(max) , varbinary(max) , of xml . We hebben nvarchar(max) . gespecificeerd en dus de waarde van -1 is precies zoals verwacht.

Padmodus:laks versus streng

Het pad in het tweede argument of in de WITH clausule kan (optioneel) beginnen met de lax of strict zoekwoord.

  • In lax modus, OPENJSON() geeft geen fout als het object of de waarde op het opgegeven pad niet kan worden gevonden. Als het pad niet kan worden gevonden, OPENJSON() geeft een lege resultaatset of een NULL . terug waarde.
  • In strict modus, OPENJSON() geeft een foutmelding als het pad niet kan worden gevonden.

De standaardwaarde is lax , dus als u geen padmodus opgeeft, lax modus zal worden gebruikt.

Hier zijn enkele voorbeelden om te laten zien wat er met elke modus gebeurt als het pad niet kan worden gevonden.

Tweede argument

In de volgende twee voorbeelden geef ik een niet-bestaand pad in het tweede argument bij het aanroepen van OPENJSON() . Het eerste voorbeeld laat zien wat er gebeurt bij het gebruik van de lax-modus, het tweede voorbeeld laat zien wat er gebeurt bij het gebruik van de strikte modus.

Lax-modus

Dit is wat er gebeurt in lax modus wanneer het pad niet kan worden gevonden.

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

Resultaat:

(0 rows affected)

Geen fout. Slechts nul resultaten geretourneerd.

Strikte modus

Nu is het hier 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');

Resultaat:

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

Zoals verwacht resulteerde de strikte modus in een fout.

In de MET-clausule

In de volgende twee voorbeelden testen we opnieuw de lakse modus versus de strikte modus, maar deze keer specificeren we het in de WITH clausule bij het definiëren van het schema.

Lax-modus

Dit is wat er gebeurt 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   
    );

Resultaat:

+----------+------------+--------+------------------------------------------------------+
| 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 dit geval gebruik ik 'lax $.born' omdat ik probeer te verwijzen naar een sleutel met de naam born , maar zo'n sleutel bestaat niet in de JSON.

Deze keer resulteert de kolom die niet kan worden gevonden in een NULL waarde.

Strikte modus

Nu is het hier 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   
    );

Resultaat:

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

Deze keer gebruikte ik 'strict $.born' .

Zoals verwacht resulteerde de strikte modus in een fout.

Compatibiliteitsniveau

De OPENJSON() functie is alleen beschikbaar onder compatibiliteitsniveau 130 of hoger.

Als uw databasecompatibiliteitsniveau lager is dan 130, kan SQL Server OPENJSON() niet vinden en uitvoeren. , en je krijgt een foutmelding.

U kunt uw databasecompatibiliteitsniveau controleren via de sys.databases catalogusweergave.

U kunt het compatibiliteitsniveau als volgt wijzigen:

ALTER DATABASE DatabaseName 
SET COMPATIBILITY_LEVEL = 150;

Nieuw bij JSON?

Als je niet zo bekend bent met JSON, bekijk dan mijn JSON-zelfstudie op Quackit.


  1. Inhoud van databasebestand bekijken in Android Studio

  2. Hekaton met een twist:In-memory TVP's – Deel 2

  3. Hoe gebruik je COUNT in SQL?

  4. Java-type voor datum/tijd bij gebruik van Oracle Date met Hibernate