Parse JSON in Microsoft SQL - json

I have the following JSON,
And I have no clue as to how to parse "Value" (When you run it in SQL you get 3 columns key, value and type)
Any ideas?
DECLARE #json NVARCHAR(MAX);
SET #json = N'[
{"salesDate":"2020-03-02","storeSales":[
{"storeId":"104","sales":[
{"productId":"20002","salesVolume":0.700,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"74301","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"642401","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"784001","salesVolume":2.100,"salesQuantity":3,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1013801","salesVolume":1.500,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1202801","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1209901","salesVolume":0.700,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1282201","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"3317301","salesVolume":1.500,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"4801301","salesVolume":0.700,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"5780106","salesVolume":6.000,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"7964902","salesVolume":0.375,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"10785001","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"11037501","salesVolume":1.500,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}}]}]}]';
SELECT *
FROM OPENJSON(#json)

Assuming you wanted to get the sales data try this (although I am not 100% sure if this query offers the best performance)
SELECT [SalesDate], [StoreId], [ProductId], [SalesVolume], [SalesQuantity]
FROM OPENJSON(#json) WITH (
[SalesDate] DATETIME '$.salesDate',
[StoreSales] NVARCHAR(MAX) '$.storeSales' AS JSON
)
OUTER APPLY OPENJSON(StoreSales) WITH (
[StoreId] INT '$.storeId',
[Sales] NVARCHAR(MAX) '$.sales' AS JSON
)
OUTER APPLY OPENJSON(Sales) WITH (
[ProductId] INT '$.productId',
[SalesVolume] DECIMAL(18, 4) '$.salesVolume',
[SalesQuantity] INT '$.salesQuantity'
)

Value is the first object in your JSON array, which is itself another JSON object. SO you will have to read it using other SQL Server JSON utilities. For example:
SELECT JSON_VALUE(Value, '$.salesDate')
FROM OPENJSON(#json)

Related

parsing json values in sql server

I want to parse the below json values.
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[{"ID":1,"Roles":[1,2]},{"ID":2"Roles":[1,2,3]},{"ID":3,"Roles":[1,2,3,4]}]'
i want to display below output
Required Output
ID ROLES
1 1
1 2
2 1
2 2
2 3
3 1
3 2
3 3
3 4
I want query for this.
An OPENJSON with a WITH unrolls the outer layer, then a regular one can be used to unroll the arrays. (The alias isn't strictly necessary, I just think it's clearer, and it becomes necessary if you have to peel even more layers.)
SELECT ID, R.[Value] AS [Role]
FROM OPENJSON(#json) WITH (
ID INT,
[Roles] NVARCHAR(MAX) AS JSON
)
CROSS APPLY OPENJSON([Roles]) R
Try this:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[{"ID":1,"Roles":[1,2]},{"ID":2, "Roles":[1,2,3]},{"ID":3,"Roles":[1,2,3,4]}]'
SELECT pvt.[ID]
,roles.value
FROM
(
SELECT js.[key] as [key_id]
,roles.[key]
,roles.value
FROM OPENJSON(#json) js
CROSS APPLY OPENJSON(js.value) roles
) DS
PIVOT
(
MAX([value]) FOR [key] IN ([ID], [Roles])
) PVT
CROSS APPLY OPENJSON(pvt.roles) roles
or just this:
SELECT JSON_VALUE(js.value, '$.ID')
,ds.[value]
FROM OPENJSON(#json) js
CROSS APPLY OPENJSON(JSON_QUERY(js.value, '$.Roles')) ds;

Check for unique JSON keys in SQL Server

In SQL Server, how can I check if a string is valid JSON and the keys are all unique?
According to the T-SQL documentation, the regular ISJSON method does not check that the keys on the same level are unique.
You can use a Recursive Common Table Expression to do this. EG something like:
DECLARE #json NVARCHAR(4000) = N'{
"StringValue":"John",
"IntValue":45,
"TrueValue":true,
"FalseValue":false,
"NullValue":null,
"ArrayValue":["a","r","r","a","y"],
"ObjectValue":{"obj":"ect"}
}';
with q as
(
select [key] path, [key], value, type, 0 level
from openjson(#json)
union all
select concat(q.path,'\',n.[key]), n.[key], n.value, n.type, q.level + 1
from q
cross apply openjson(q.value) n
where q.type in (4,5)
)
select *, count(*) over (partition by path) pathCount
from q

Extract data from Json string and divide into multiple columns

I have a column in a table that has Jsonstring text:
[
{
"PType":{"code":"9","name":"Hospitality"},
"PSubType":{"code":"901","name":"Hotel"},
"AType":{"code":"9","name":"Hospitality"},
"ASubType":{"code":"901","name":"Hotel"}
}
]
How can I divide that into multiple columns using sql server query?
With SQL-Server 2016+ there is native JSON support:
DECLARE #json NVARCHAR(MAX)=
N'[
{
"PType":{"code":"9","name":"Hospitality"},
"PSubType":{"code":"901","name":"Hotel"},
"AType":{"code":"9","name":"Hospitality"},
"ASubType":{"code":"901","name":"Hotel"}
}
]';
SELECT A.[key]
,JSON_VALUE(A.value,'$.code') AS Code
,JSON_VALUE(A.value,'$.name') AS [Name]
FROM OPENJSON(JSON_QUERY(#json,'$[0]')) A;
The result
key Code Name
---------------------------------
PType 9 Hospitality
PSubType 901 Hotel
AType 9 Hospitality
ASubType 901 Hotel
Some explanation:
With JSON_QUERY() you can get the element within the array, OPENJSON will find all objects within and return them as derived table.
JSON_VALUE will read the internals into columns.
Hint
with a version below v2016 you should use another tool or think about a CLR function...
In SQL Server 2016+ you can use a combination of openjson (more info here) and cross apply:
declare #json nvarchar(max) = '[ { "PType":{"code":"9","name":"Hospitality"}, "PSubType":{"code":"901","name":"Hotel"}, "AType":{"code":"9","name":"Hospitality"}, "ASubType":{"code":"901","name":"Hotel"} } ]'
select
[PT].[code] as Ptype_Code
,[PT].[name] as Ptype_Name
,[PS].[code] as PSubType_Code
,[PS].[name] as PSubType_Name
,[AT].[code] as AType_Code
,[AT].[name] as AType_Name
,[AS].[code] as ASubType_Code
,[AS].[name] as ASubType_Name
from openjson (#json)
with
(
PType nvarchar(max) as json,
PSubType nvarchar(max) as json,
AType nvarchar(max) as json,
ASubType nvarchar(max) as json
) as lev1
cross apply openjson (lev1.PType)
with
(
code int,
name nvarchar(100)
) as PT
cross apply openjson (lev1.PSubType)
with
(
code int,
name nvarchar(100)
) as PS
cross apply openjson (lev1.AType)
with
(
code int,
name nvarchar(100)
) as [AT]
cross apply openjson (lev1.ASubType)
with
(
code int,
name nvarchar(100)
) as [AS]
Result:

SQL Server 2016 - How to select integer array from JSON

I received a valid JSON string from client side, it contains an array of integer values:
declare #JSON nvarchar(max) = N'{"Comments": "test", "Markets": [3, 151]}'
How to select the market IDs correctly?
If I use a query like this: select * from openjson(#JSON) j, it returns
The type of Markets is 4, which means an object,
but the query below returns null value:
select j.Markets from openjson(#JSON) with(Markets nvarchar(max)) j
My goal is to update Market table based on these IDs, eg:
update Market set Active = 1 where MarketID in (3, 151)
Is there a way to do this?
Any built-in function compatible with SQL server 2016 can be used.
Note:
Thanks to #johnlbevan
SELECT VALUE FROM OPENJSON(#JSON, '$.Markets') works perfectly for this problem.
Just for the completeness, here is how I created the JSON integer array ("Markets": [3, 151]) from SQL server.
Since there is no array_agg function out of the box in 2016, I did this:
SELECT (
JSON_QUERY('[' + STUFF(( SELECT ',' + CAST(MarketID AS VARCHAR)
FROM Market
FOR XML PATH('')),1,1,'') + ']' ) AS Markets)
To expand the Markets array alongside other columns you can do this:
SELECT Comments, Market
FROM OPENJSON('{"Comments": "test", "Markets": [3, 151]}')
WITH (Comments nvarchar(32), Markets NVARCHAR(MAX) AS JSON) AS a
CROSS APPLY OPENJSON (a.Markets) WITH (Market INT '$') AS b
Convert the string to json
Map the first field returned to the Comments column with type nvarchar(32)
Map the second field to Markets column with type nvarchar(max), then use as json to say that the contents is json (see https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql#arguments for a more detailed description - search the page for as json; the key paragraph starts at the 4th occurrence)
Use a cross apply to apply the OPENJSON function to the Markets column so we can fetch values from that property.
Finally use the WITH statement to map the name Market to the returned value, and assign it a data type of INT.
However, to just get the list of values needed to do the update, you can do this:
UPDATE Market
SET Active = 1
WHERE MarketID IN
(
SELECT value
FROM OPENJSON('{"Comments": "test", "Markets": [3, 151]}','$.Markets')
);
Again OPENJSON lets us query the string as JSON
However this time we specify a path to point at the Markets value directly (see https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql)
We now return the values returned and filter our UPDATE on those, as we would were we dealing with any other subquery.

How to read field name with space in Json using OPENJSON in SQL Server 2016

How can I read value from json file in that field name contains space using OPENJSON in Sql Server 2016. See the below code:
DECLARE #json NVARCHAR(MAX)
SET #json = N'{ "full name" : "Jayesh Tank"}';
SELECT * FROM OPENJSON(#json) WITH ( [name] [varchar](60) '$.full name')
Also another sample code in that space is after field name.
SET #json = N'{ "name " : "abc"}';
SELECT * FROM OPENJSON(#json) WITH ( [name] [varchar](60) '$.name')
'$.name' will return null.Is there way to read this value?
Generally it is a bad idea to use spaces in the attribute name.
I would leave out the [ ] from your OPENJSON name and varchar(60) - source MSDN OPENJSON.
Now to actually answer your question:
You need to format your attribute with double quotes in the WITH clause:
#DECLARE #json NVARCHAR(MAX);
SET #json=N'{ "full name" : "Jayesh Tank"}';
SELECT * FROM OPENJSON(#json) WITH (name varchar(60) '$."full name"')
for the second one:
SET #json = N'{ "name " : "abc"}';
SELECT * FROM OPENJSON(#json) WITH ( name varchar(60)'$."name "')
JSON_VALUE(c.value,'$.Serial Number') as [Serial Number] is throwing an error with a space. How do I resolve the space in the field name using JSON_VALUE .
by itself '$.Full Name' is not a valid json, but adding '$."Full Name"' the json becomes valid