SQL Server má funkci s hodnotou tabulky nazvanou OPENJSON()
který vytváří relační pohled na data JSON.
Když jej zavoláte, předáte dokument JSON jako argument a OPENJSON()
poté jej analyzuje a vrátí objekty a vlastnosti dokumentu JSON v tabulkovém formátu – jako řádky a sloupce.
Příklad
Zde je jednoduchý příklad k demonstraci.
SELECT * FROM OPENJSON('["Cat","Dog","Bird"]');
Výsledek:
+-------+---------+--------+ | key | value | type | |-------+---------+--------| | 0 | Cat | 1 | | 1 | Dog | 1 | | 2 | Bird | 1 | +-------+---------+--------+
Ve výchozím nastavení OPENJSON()
vrátí tabulku se třemi sloupci; klíč , hodnota a zadejte .
Máte také možnost zadat své vlastní schéma (což znamená, že můžete definovat své vlastní sloupce). V mém jednoduchém příkladu jsem použil výchozí schéma, a tak byly vráceny tři výchozí sloupce.
Tyto sloupce jsou definovány takto:
Sloupec | Popis |
---|---|
klíč | Obsahuje název zadané vlastnosti nebo index prvku v zadaném poli. Toto je nvarchar(4000) hodnotu a sloupec má řazení BIN2. |
hodnota | Obsahuje hodnotu vlastnosti. Toto je nvarchar(max) hodnotu a sloupec zdědí své řazení z poskytnutého JSON. |
typ | Obsahuje typ JSON hodnoty. Toto je reprezentováno jako int hodnota (od 0 až 5 ). Tento sloupec je vrácen pouze při použití výchozího schématu. |
Výchozí typy
Ve světě JSON existuje šest datových typů. Jedná se o řetězec , číslo , pravda/nepravda (logická hodnota), null , objekt a pole .
Když analyzujete nějaký JSON prostřednictvím OPENJSON()
pomocí výchozího schématu OPENJSON()
zjistí, jaký je typ JSON, a poté vyplní typ sloupec s int hodnotu, která tento typ představuje.
int hodnota se proto může pohybovat od 0
až 5
. Každý int value představuje typ JSON, jak je uvedeno v následující tabulce.
Hodnota ve sloupci „typ“ | Datový typ JSON |
---|---|
0 | null |
1 | řetězec |
2 | číslo |
3 | pravda/nepravda |
4 | pole |
5 | objekt |
Následující příklad vrátí všech šest těchto typů JSON.
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}]');
Výsledek:
+-------+---------+--------+ | 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)
Vrátit vnořený JSON
Vnořený objekt nebo pole můžete vrátit zadáním jeho cesty jako volitelného druhého argumentu.
Jinými slovy, nemusíte analyzovat celý dokument JSON – můžete se rozhodnout analyzovat pouze tu část, která vás zajímá.
Zde je příklad.
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');
Výsledek:
+-------+------------------------------------------------------+--------+ | 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 | +-------+------------------------------------------------------+--------+
V tomto případě jsem zadal cestu $.pets.cats
, což vedlo pouze k hodnotě koček vracení. Hodnota koček je pole, takže bylo vráceno celé pole.
Chcete-li vrátit pouze jednu kočku (tj. jeden prvek pole), můžeme pro vrácení hodnot pole použít syntaxi hranatých závorek (jako tento $.pets.cats[1]
).
Zde je stejný příklad upravený tak, aby vrátil pouze jeden prvek pole:
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]');
Výsledek:
+-------+-----------+--------+ | key | value | type | |-------+-----------+--------| | id | 2 | 2 | | name | Long Tail | 1 | | sex | Female | 1 | +-------+-----------+--------+
Indexy pole JSON jsou založeny na nule, takže tento příklad vrátil druhou hodnotu pole (protože jsem zadal $.pets.cats[1]
).
Kdybych zadal $.pets.cats[0]
, byla by vrácena první hodnota (tj. kočka s názvem „Fluffy“).
Definujte schéma
Jak již bylo zmíněno, můžete zadat své vlastní schéma (tj. definovat vlastní sloupce a typy).
Zde je příklad, jak to udělat.
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
);
Výsledek:
+----------+------------+--------+------------------------------------------------------+ | 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" } | +----------+------------+--------+------------------------------------------------------+
Vidíme, že názvy sloupců odpovídají těm, které jsem zadal v WITH
doložka. V této klauzuli jsem namapoval každý klíč JSON na vlastní preferované názvy sloupců. Také jsem určil typ dat serveru SQL Server, který chci pro každý sloupec.
Také jsem použil AS JSON
na posledním sloupci, aby se tento sloupec vrátil jako fragment JSON. Když používáte AS JSON, typ dat musí být nvarchar(max) .
Ověřte datové typy
K ověření datových typů každého sloupce můžeme použít následující dotaz.
Tento dotaz používá sys.dm_exec_describe_first_result_set
zobrazení dynamické správy systému, které vrací metadata o první sadě výsledků z dotazu.
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
);
Výsledek:
+----------+--------------------+ | name | system_type_name | |----------+--------------------| | Cat Id | int | | Cat Name | varchar(60) | | Sex | varchar(6) | | Cats | nvarchar(max) | +----------+--------------------+
Vidíme, že dokonale odpovídají mému schématu.
Všimněte si, že klíč , hodnota a zadejte Při definování vlastního schématu nejsou sloupce dostupné. Tyto sloupce jsou dostupné pouze při použití výchozího schématu.
Vložte analyzovaný JSON do tabulky
Nyní si možná myslíte, že bychom mohli náš analyzovaný JSON snadno vložit do databázové tabulky.
A měli byste pravdu.
Již jsme jej připravili se sloupci a řádky a dokonce jsme sloupce pojmenovali a dali jim datové typy.
Nyní je čas jej vložit do tabulky.
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
);
Vše, co jsem udělal, bylo přidat INTO JsonCats
na můj dotaz, za účelem vytvoření tabulky s názvem JsonCats
a vložte do něj výsledky dotazu.
Nyní vybereme obsah této tabulky.
SELECT * FROM JsonCats;
Výsledek:
+----------+------------+--------+------------------------------------------------------+ | 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" } | +----------+------------+--------+------------------------------------------------------+
Obsah je přesně takový, jaký jsme viděli v předchozím příkladu.
A pro naprostou jistotu nyní můžeme použít sys.column
zobrazení systémového katalogu zkontrolujte názvy a typy sloupců tabulky.
SELECT
name AS [Column],
TYPE_NAME(system_type_id) AS [Type],
max_length
FROM sys.columns
WHERE OBJECT_ID('JsonCats') = object_id;
Výsledek:
+----------+----------+--------------+ | Column | Type | max_length | |----------+----------+--------------| | Cat Id | int | 4 | | Cat Name | varchar | 60 | | Sex | varchar | 6 | | Cats | nvarchar | -1 | +----------+----------+--------------+
Opět přesně tak, jak jsme to specifikovali.
Všimněte si, že sys.columns
vždy vrátí max_length
z -1
když je datový typ sloupce varchar(max) , nvarchar(max) , varbinary(max) nebo xml . Zadali jsme nvarchar(max) a tedy hodnotu -1
je přesně podle očekávání.
Režim cesty:Laxní versus přísný
Cesta uvedená ve druhém argumentu nebo v WITH
klauzule může (volitelně) začínat lax
nebo strict
klíčové slovo.
- V
lax
režim,OPENJSON()
nevyvolá chybu, pokud nelze objekt nebo hodnotu na zadané cestě nalézt. Pokud cestu nelze najít,OPENJSON()
vrátí buď prázdnou sadu výsledků, neboNULL
hodnotu. - V
strict
režim,OPENJSON()
vrátí chybu, pokud cestu nelze najít.
Výchozí hodnota je lax
, takže pokud neurčíte režim cesty, lax
bude použit režim.
Zde je několik příkladů, které demonstrují, co se stane s každým režimem, když nelze najít cestu.
Druhý argument
V následujících dvou příkladech uvádím neexistující cestu ve druhém argumentu při volání OPENJSON()
. První příklad ukazuje, co se stane při použití laxního režimu, druhý příklad ukazuje, co se stane při použití přísného režimu.
Laxní režim
Zde je to, co se děje v lax
režimu, když cestu nelze najít.
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');
Výsledek:
(0 rows affected)
Žádná chyba. Vrátily se pouze nulové výsledky.
Přísný režim
Nyní je zde v strict
režimu.
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');
Výsledek:
Msg 13608, Level 16, State 3, Line 15 Property cannot be found on the specified JSON path.
Podle očekávání vedl přísný režim k chybě.
V klauzuli WITH
V následujících dvou příkladech opět testujeme laxní režim vs. přísný režim, tentokrát to však specifikujeme v WITH
klauzule při definování schématu.
Laxní režim
Zde je to, co se děje v lax
režimu.
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
);
Výsledek:
+----------+------------+--------+------------------------------------------------------+ | 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" } | +----------+------------+--------+------------------------------------------------------+
V tomto případě používám 'lax $.born'
protože se snažím odkazovat na klíč s názvem born
, ale takový klíč v JSON neexistuje.
Tentokrát má sloupec, který nelze najít, za následek NULL
hodnotu.
Přísný režim
Nyní je zde v strict
režimu.
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
);
Výsledek:
Msg 13608, Level 16, State 6, Line 16 Property cannot be found on the specified JSON path.
Tentokrát jsem použil 'strict $.born'
.
Podle očekávání vedl přísný režim k chybě.
Úroveň kompatibility
OPENJSON()
Funkce je dostupná pouze při úrovni kompatibility 130 nebo vyšší.
Pokud je úroveň kompatibility vaší databáze nižší než 130, SQL Server nebude schopen najít a spustit OPENJSON()
a zobrazí se chyba.
Úroveň kompatibility databáze můžete zkontrolovat prostřednictvím sys.databases
zobrazení katalogu.
Úroveň jeho kompatibility můžete změnit takto:
ALTER DATABASE DatabaseName
SET COMPATIBILITY_LEVEL = 150;
Nová verze JSON?
Pokud nejste s JSON tak obeznámeni, podívejte se na můj JSON tutoriál na Quackit.