sql >> Database teknologi >  >> RDS >> Sqlserver

Sådan vælger du indlejret JSON i SQL Server med OPENJSON

Hvis du bruger OPENJSON() , men du prøver at huske, hvordan du vælger et indre fragment fra JSON-dokumentet, læs videre.

OPENJSON() syntaks giver dig mulighed for at konvertere JSON-dokumenter til en tabelvisning. Det giver dig også mulighed for at vælge et indlejret JSON-fragment fra JSON-dokumentet.

Måden at gøre dette på er med stier .

Stier

En sti består af følgende:

  • Et dollartegn ($ ), som repræsenterer kontekstelementet.
  • Et sæt stitrin. Stitrin kan indeholde følgende elementer og operatorer:
    • Nøglenavne. For eksempel $.pets og $.pets.dogs . Hvis nøglenavnet starter med et dollartegn eller indeholder specialtegn såsom mellemrum, skal det være omgivet af anførselstegn (for eksempel $."my pets" ).
    • Array-elementer. For eksempel $.pets.dogs[1] . Array-indekser er nul-baserede, så dette eksempel vælger det andet element i arrayet.
    • Prikoperatoren (. ) angiver et medlem af et objekt. For eksempel i $.pets.dogs , dogs er medlem af pets .

Grundlæggende eksempel

Her er et simpelt eksempel at demonstrere.

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

Resultat:

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

I dette tilfælde er det andet argument til OPENJSON() er '$.pets.dogs' , hvilket betyder, at vi vælger værdien af ​​dogs nøgle, som selv er et barn af pets .

Dollartegnet ($ ) repræsenterer kontekstelementet.

Bemærk, at i dette eksempel bruger jeg også WITH klausul for at definere skemaet. Hvis jeg ikke inkluderede det, ville standardskemaet blive brugt i stedet.

Sådan ser det ud med standardskemaet.

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

Resultat:

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

Så vi vælger stadig den samme indlejrede JSON, det er bare, at vi bruger et andet skema.

Standardskemaet returnerer altid tre kolonner; tast , værdi , og skriv .

Valg af matrixelementer

Som nævnt kan du bruge notationen med firkantede parenteser til at vælge et specifikt element i en matrix.

Her er et eksempel.

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

Resultat:

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

Da array-indekser er nul-baserede, angiver værdien 0 returnerer det første element i arrayet.

Sådan ser dette eksempel ud, når du bruger standardskemaet (dvs. uden WITH klausul).

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

Resultat:

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

Stitilstand

Når du bruger stier, har du mulighed for at erklære stitilstanden.

Stitilstand bestemmer, hvad der sker, når et stiudtryk indeholder en fejl.

Stitilstand kan enten være lax eller strict .

  • I lax tilstand, returnerer funktionen tomme værdier, hvis stien ikke kan findes. For eksempel, hvis du anmoder om værdien $.pets.cows , men JSON'en indeholder ikke den nøgle, returnerer funktionen null, men frembringer ikke en fejl.
  • I strict tilstand, rejser funktionen en fejl, hvis stien ikke kan findes.

Standardstitilstanden er lax , så hvis du ikke erklærer det, lax anvendes.

Eksempel

Her er et eksempel for at demonstrere, hvordan hver stitilstand håndterer manglende stier.

Laks tilstand

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

Resultat:

(0 rows affected)

Så slap tilstand gav ingen fejl. Det resulterede simpelthen i, at nul rækker blev påvirket.

Hvis vi specificerede vores eget skema, og vi valgte det korrekte underobjekt, men vi brugte en manglende sti til at tilknytte et kolonnenavn, ville det returnere NULL i den kolonne.

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

Resultat:

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

Strikt tilstand

Her er, hvad der sker, når vi bruger streng tilstand.

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

Resultat:

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

Som forventet resulterede det i en fejl.

Den samme fejl opstår, når vi vælger den korrekte JSON-nøgle, men knytter en kolonne til en ikke-eksisterende nøgle.

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

Resultat:

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

Dublerede stier

Hvis dit JSON-dokument indeholder duplikerede stier på samme indlejringsniveau, OPENJSON() kan returnere dem alle.

Dette er i modsætning til JSON_VALUE() og JSON_QUERY() , som begge kun returnerer den første værdi, der matcher stien.

Her er et eksempel på brug af OPENJSON() for at returnere duplikerede stier.

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

Resultat:

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

Indlejrede underobjekter

Når du definerer dit eget skema, kan du bruge AS JSON mulighed for at returnere et helt underobjekt som sit eget JSON-dokument.

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

Resultat:

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

Hvis vi ikke havde brugt AS JSON mulighed, ville vi have modtaget en fejl eller NULL, afhængigt af om vi havde angivet lax eller strict tilstand.

Her er det i hver tilstand, når du udelader AS JSON mulighed.

Laks tilstand

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

Resultat:

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

Strikt tilstand

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

Resultat:

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

  1. Arbejde med SQL-markører

  2. Sådan rettes "Procedure forventer parameter '@statement' af typen 'ntext/nchar/nvarchar'." Fejl i SQL Server

  3. SQL GROUP BY CASE-sætning med aggregeret funktion

  4. Den vedhæftede database er skrivebeskyttet