Pro JSON není v SQL serveru spciální datový typ. Používá se NVARCHAR(MAX), JSON formát můžu vynutit constraintem pomocí funkce ISJSON.
Jako přiklad si udělám tempovou tabulku s constraintem
CREATE TABLE #json( JSONData NVARCHAR(MAX) NOT NULL CONSTRAINT check_JSONData_is_json CHECK (ISJSON(JSONData) = 1) ) GO
Pokusím se vložit něco, co není JSON
INSERT INTO #json(JSONData) VALUES('nesmysl')
GO
--The INSERT statement conflicted with the CHECK constraint "check_JSONData_is_json". The conflict occurred in database "tempdb", table "dbo.#json_______________________________________________________________________________________________________________000000000067", column 'JSONData'.
Založím testovací data
INSERT INTO #json(JSONData) VALUES(
N'
[
{
"jmeno": "Kamil",
"prijmeni": "Skočdopole",
"konicky": [
"šachy",
"sport",
"vážná hudba"
],
"adresy": [
{
"typ": "bydliště",
"mesto": "Frenštát pod Radhoštěm",
"cp": "10"
},
{
"typ": "doručovací",
"mesto": "Ostrava",
"cp": "50"
}
],
"hodne pije": true,
"telesna_teplota": 36.9,
"zbrojni_pas":null
},
{
"jmeno": "Uršula",
"prijmeni": "Králová",
"konicky": [
"pletení",
"ultramaraton"
],
"adresy": [
{
"typ": "bydliště",
"mesto": "Frenštát pod Radhoštěm",
"cp": "10"
}
]
}
]
'
)
SELECT * FROM #json
Otestování, zda máme validní JSON
SELECT ISJSON((SELECT * FROM #json))--vrací 1
JSON_QUERY vrací JSON objekt, nebo pole
SELECT JSON_QUERY((SELECT * FROM #json)) SELECT JSON_QUERY((SELECT * FROM #json), '$[0].adresy') SELECT JSON_QUERY((SELECT * FROM #json), '$[1].adresy') SELECT JSON_QUERY((SELECT * FROM #json), '$[1].konicky')
Striktní vs. laxní mód
By deafault je laxní
--NULL, protoze jmeno je hodnota a ne objekt SELECT JSON_QUERY((SELECT * FROM #json), '$[0].jmeno') --NULL, protoze jmeno je hodnota a ne objekt SELECT JSON_QUERY((SELECT * FROM #json), 'lax $[0].jmeno') --Object or array cannot be found in the specified JSON path. SELECT JSON_QUERY((SELECT * FROM #json), 'strict $[0].jmeno')
JSON_VALUE vrací hodnotu NVARCHAR(4000)
SELECT JSON_VALUE((SELECT * FROM #json), '$[0].jmeno')--Kamil
Pokud je v názvu atributu mezera, tak ho musím mít v uvozovkách
--JSON path is not properly formatted. Unexpected character ' ' is found at position 10. SELECT JSON_VALUE((SELECT * FROM #json), '$[0].hodne pije') --true SELECT JSON_VALUE((SELECT * FROM #json), '$[0]."hodne pije"')
Neexistující atribut je problém rozeznat od atributu s NULL hodnotou
--NULL SELECT JSON_VALUE((SELECT * FROM #json), '$[0].neexistujici') --Property cannot be found on the specified JSON path. SELECT JSON_VALUE((SELECT * FROM #json), 'strict $[0].neexistujici')
Atribut s NULL hodnotou
--NULL SELECT JSON_VALUE((SELECT * FROM #json), '$[0].zbrojni_pas') --NULL SELECT JSON_VALUE((SELECT * FROM #json), 'strict $[0].zbrojni_pas')
OPENJSON
Další možností čtení JSONu je s použitím funkce OPENJSON. Umožňuje přečíst více než 4000 znaků a vracet data v tabulkové podobě.
Syntaxe je:
OPENJSON( jsonExpression [ , path ] ) [ <with_clause> ]
SELECT * FROM OPENJSON((SELECT * FROM #json))
Výsledkem je tabulka se sloupci key, value, type

- key
- název atributu, nebo pořadové číslo v poli
- value
- hodnota
- type
-
0 NULL Rozumná cesta jak rozlišit hodnotu NULL od neexistujícího atributu
1 string
2 číslo
3 boolean
4 pole
5 objekt
Dá se k tomu doplnit cesta
SELECT * FROM OPENJSON((SELECT * FROM #json),'$[0]')
SELECT * FROM OPENJSON((SELECT * FROM #json),'$[0].konicky')
Doplněním WITH kluzule uděláme z JSON tabulku, kde budou atributy ve sloupcích
Syntaxe:
<with_clause> ::= WITH ( { colName type [ column_path ] [ AS JSON ] } [ ,...n ] )
SELECT * FROM OPENJSON((SELECT * FROM #json)) WITH( jmeno NVARCHAR(50), prijmeni NVARCHAR(50), [hodne pije] BIT, nesmysl NVARCHAR(50), zbrojni_pas BIT )
Můžeme doplnit column_path a přejmenovat si na vlastní colName
SELECT * FROM OPENJSON((SELECT * FROM #json)) WITH( jmeno NVARCHAR(50) '$.jmeno', prijmeni NVARCHAR(50) '$.prijmeni', [ochlasta] BIT '$."hodne pije"', nesmysl NVARCHAR(50) '$.nesmysl', zbrojni_pas BIT '$.zbrojni_pas', prvniKonicek NVARCHAR(250) '$.konicky[0]', mesto NVARCHAR(250) '$.adresy[0].mesto' )

Pokud chceme vrátit JSON, nebo pole, tak musíme použít AS JSON, jinak dostaneme NULL
SELECT * FROM OPENJSON((SELECT * FROM #json)) WITH( jmeno NVARCHAR(50) '$.jmeno', prijmeni NVARCHAR(50) '$.prijmeni', [ochlasta] BIT '$."hodne pije"', nesmysl NVARCHAR(50) '$.nesmysl', zbrojni_pas BIT '$.zbrojni_pas', adresy1 NVARCHAR(MAX) '$.adresy', --pokud je tam objekt, nebo pole, --tak nevrátí nic v lax modu. strict by spadnul adresy2 NVARCHAR(MAX) '$.adresy' AS JSON --je potřeba použít AS JSON )
Vrácený JSON z první funkce můžeme dál rozebrat pomocí APPLY OPENSJON
SELECT * FROM OPENJSON((SELECT * FROM #json)) WITH( jmeno NVARCHAR(50) '$.jmeno', prijmeni NVARCHAR(50) '$.prijmeni', [ochlasta] BIT '$."hodne pije"', nesmysl NVARCHAR(50) '$.nesmysl', zbrojni_pas BIT '$.zbrojni_pas', adresy NVARCHAR(MAX) '$.adresy' AS JSON )pole OUTER APPLY OPENJSON(pole.adresy) WITH( typ NVARCHAR(50) , mesto NVARCHAR(50) , cp NVARCHAR(50) )















