I'm trying to parse the 'custinfo' array to rows, rather than specific columns how I have in my query (there can be none or many values in the array)
DECLARE #json NVARCHAR(MAX) ='{
"customer": [
{
"id": "123",
"history": [
{
"id": "a123",
"dates": [
{
"date": "2022-03-19",
"details": {
"custinfo": [
"male",
"married"
],
"age": 40
}}]}]}]}'
SELECT
JSON_VALUE ( j.[value], '$.id' ) AS CustId,
JSON_VALUE ( m.[value], '$.id' ) AS CustId_Hist,
JSON_VALUE ( a1.[value], '$.date' ) AS date,
JSON_VALUE ( a1.[value], '$.details.age' ) AS age,
JSON_VALUE ( a1.[value], '$.details.custinfo[0]' ) AS custinfo0,
JSON_VALUE ( a1.[value], '$.details.custinfo[1]' ) AS custinfo1
FROM OPENJSON( #json, '$."customer"' ) j
CROSS APPLY OPENJSON ( j.[value], '$."history"' ) AS m
CROSS APPLY OPENJSON ( m.[value], '$."dates"' ) AS a1
Desired results:
Like I mentioned in the comments, I would switch to using WITH clauses and defining your columns and their data types. You can then also get the values, into 2 separate rows you want, with the following. Note tbhe extra OPENJSON at the end, which treats the custinfo as the array it is; returning 2 rows (1 for each value in the array):
DECLARE #json NVARCHAR(MAX) ='{
"customer": [
{
"id": "123",
"history": [
{
"id": "a123",
"dates": [
{
"date": "2022-03-19",
"details": {
"custinfo": [
"male",
"married"
],
"age": 40
}}]}]}]}';
SELECT c.id AS CustId,
h.id AS CustId_Hist,
d.date AS date,
d.age AS age,
ci.[value] AS custinfo
FROM OPENJSON( #json,'$.customer')
WITH (id int,
history nvarchar(MAX) AS JSON) c
CROSS APPLY OPENJSON (c.history)
WITH (id varchar(10),
dates nvarchar(MAX) AS JSON) h
CROSS APPLY OPENJSON (h.dates)
WITH(date date,
details nvarchar(MAX) AS JSON,
age int '$.details.age') d
CROSS APPLY OPENJSON(d.details,'$.custinfo') ci;
Related
I'm working on parsing JSON document with an object array into a SQL Server table. I'm stuck with how to parse the complex object array.
I tried subproject.id and that did not work. I usually use the below code to parse a JSON array which works just fine but in this case it does not.
JSON:
{
"Data": [
{
"name": "ABC",
"date": "2020-01-20",
"subproject": [
{
"id": "123",
"projectname": "new1",
"refnum": "123:new1"
},
{
"id": "456",
"projectname": "new2",
"refnum": "456:new2"
}
],
"projectid": "1234",
"projectdate": "2020-01-27"
},
{
"name": "DEF",
"date": "2020-01-30",
"subproject": [
{
"id": "789",
"projectname": "new3",
"refnum": "789:new3"
},
{
"id": "901",
"projectname": "new4",
"refnum": "901:new4"
}
],
"projectid": "4567",
"projectdate": "2020-02-07"
}
]
}
SQL:
DECLARE #JSON VARCHAR(MAX)
SELECT #JSON = BulkColumn
FROM OPENROWSET (BULK 'c:/data/project.json', SINGLE_CLOB) X
SELECT *
FROM OPENJSON (#JSON)
WITH (
[name] NVARCHAR(256),
[date] DATE,
[projectid] INT,
[projectdate] DATE
)
You need to use AS JSON clause in the first OPENJSON() call (to specify that the $.subproject property contains an inner JSON array) and a combination of another OPENJSON() call and APPLY operator:
SELECT *
FROM OPENJSON (#JSON, '$.Data') WITH (
[name] NVARCHAR(256),
[date] DATE,
[projectid] INT,
[projectdate] DATE,
[subproject] NVARCHAR(MAX) '$.subproject' AS JSON
) j1
OUTER APPLY OPENJSON (j1.[subproject]) WITH (
[subprojectid] INT '$.id',
[subprojectname] NVARCHAR(256) '$.projectname',
[subprojectrefnum] NVARCHAR(256) '$.refnum'
) j2
I'm parsing a JSON dataset within SQL Server and it works great with a single object, but falls down when multiple data objects are presented. I assume it's because of the CROSS APPLY statements.
Within the JSON dataset, there is only 4 records, but my current sql is returning 16 (4 duplicate sets, as there are 4 cross apply statements), but I'm not sure how to get around this?
json
{
"type": "test",
"user": {
"last_update": "2022-06-19T14:13:07.707502+00:00",
"user_id": "12345"
},
"data": [
{
"metadata": {
"start_time": "2022-06-19T00:00:00+01:00",
"end_time": "2022-06-20T00:00:00+01:00"
},
"distance_data": {
"steps": 9299,
"distance_meters": 7704.0
}
},
{
"metadata": {
"start_time": "2022-06-17T00:00:00+01:00",
"end_time": "2022-06-18T00:00:00+01:00"
},
"distance_data": {
"steps": 2546,
"distance_meters": 2143.0
}
},
{
"metadata": {
"start_time": "2022-06-16T00:00:00+01:00",
"end_time": "2022-06-17T00:00:00+01:00"
},
"distance_data": {
"steps": 4969,
"distance_meters": 4192.0
}
},
{
"metadata": {
"start_time": "2022-06-18T00:00:00+01:00",
"end_time": "2022-06-19T00:00:00+01:00"
},
"distance_data": {
"steps": 6769,
"distance_meters": 5698.0
}
}
]
}
SQL statement
SELECT
distance_meters, steps, cast(left(start_time,10) as date) startDate
FROM
OPENJSON ( #json )
WITH (
jType nvarchar(50) N'$.type',
jUser char(36) N'$.user.user_id',
data nvarchar(max) as JSON
) as a
CROSS APPLY
OPENJSON(a.data)
WITH
(
distance_data nvarchar(max) as json
) as b
CROSS APPLY
OPENJSON (b.distance_data)
WITH
(
distance_meters float,
steps int
) as c
CROSS APPLY
OPENJSON (a.data)
WITH
(
metadata nvarchar(max) as json
) as d
CROSS APPLY
OPENJSON (d.metadata)
WITH
(
start_time nvarchar(25),
end_time nvarchar(25)
) as e
ORDER BY startDate ASC;
I think you need a single APPLY operator:
SELECT j1.jType, j1.jUser, j2.*
FROM OPENJSON(#json) WITH (
jType nvarchar(50) N'$.type',
jUser char(36) N'$.user.user_id',
data nvarchar(max) as JSON
) AS j1
CROSS APPLY OPENJSON(j1.data) WITH (
start_time nvarchar(25) '$.metadata.start_time',
end_time nvarchar(25) '$.metadata.end_time',
steps numeric(10, 0) '$.distance_data.steps',
distance_meters numeric(10, 1) '$.distance_data.distance_meters'
) j2
Result:
jType
jUser
start_time
end_time
steps
distance_meters
test
12345
2022-06-19T00:00:00+01:00
2022-06-20T00:00:00+01:00
9299
7704.0
test
12345
2022-06-17T00:00:00+01:00
2022-06-18T00:00:00+01:00
2546
2143.0
test
12345
2022-06-16T00:00:00+01:00
2022-06-17T00:00:00+01:00
4969
4192.0
test
12345
2022-06-18T00:00:00+01:00
2022-06-19T00:00:00+01:00
6769
5698.0
I have a problem with JSON data and how to get it in SQL table so the data is:
[
{
"id":"1121131",
"idGroups":[
"123",
"X999"
],
"idGroupNames":[
"Neutral",
"Service"
]
},
{
"id":"2233154",
"idGroups":[
"654321"
],
"idGroupNames":[
"Position"
]
}
]
and the desired output is
Id
idGroups
idGroupNames
1121131
123
Neutral
1121131
X999
Service
2233154
654321
Position
I have trying to get the desired result with OPENJSON() and CROSS APPLY, but I think that I'm not getting anywhere.
my original attempt was
DECLARE #json NVARCHAR(MAX) = N'[
{
"id":"1121131",
"idGroups":[
"123",
"X999"
],
"idGroupNames":[
"Neutral",
"Service"
]
},
{
"id":"2233154",
"idGroups":[
"654321"
],
"idGroupNames":[
"Position"
]
}
]'
SELECT id,idGroup,idGroupName FROM OPENJSON (#json)
WITH (
id INT 'strict $.id',
idGroups NVARCHAR(MAX) '$.idGroups' AS JSON,
idGroupNames NVARCHAR(MAX) '$.idGroupNames' AS JSON
) CROSS APPLY OPENJSON(idGroups)
WITH (
idGroup VARCHAR(500) '$'
) CROSS APPLY OPENJSON(idGroupNames)
WITH (
idGroupName VARCHAR(500) '$'
)
You need to use OPENJSON() with default schema and two additional APPLY operators. The following statement is a possible solution to your problem:
JSON:
DECLARE #json nvarchar(max) = N'[
{
"id":"1121131",
"idGroups":[
"123",
"X999"
],
"idGroupNames":[
"Neutral",
"Service"
]
},
{
"id":"2233154",
"idGroups":[
"654321"
],
"idGroupNames":[
"Position"
]
}
]'
Statement:
SELECT j.id, j1.[value] AS idGroups, j2.[value] AS idGroupNames
FROM OPENJSON(#json) WITH (
id nvarchar(7) '$.id',
idGroups nvarchar(max) '$.idGroups' AS JSON,
idGroupNames nvarchar(max) '$.idGroupNames' AS JSON
) j
CROSS APPLY OPENJSON(j.idGroups) j1
CROSS APPLY OPENJSON(j.idGroupNames) j2
WHERE j1.[key] = j2.[key]
You can do it without a third OPENJSON, using JSON_VALUE and a dynamic path.
This only works in SQL Server 2017+
DECLARE #json nvarchar(max) = N'[
{
"id":"1121131",
"idGroups":[
"123",
"X999"
],
"idGroupNames":[
"Neutral",
"Service"
]
},
{
"id":"2233154",
"idGroups":[
"654321"
],
"idGroupNames":[
"Position"
]
}
]';
SELECT j.id, j1.[value] AS idGroups, JSON_VALUE(j.idGroupNames, '$[' + j1.[key] + ']') AS idGroupNames
FROM OPENJSON(#json) WITH (
id nvarchar(7) '$.id',
idGroups nvarchar(max) '$.idGroups' AS JSON,
idGroupNames nvarchar(max) '$.idGroupNames' AS JSON
) j
CROSS APPLY OPENJSON(j.idGroups) j1;
db<>fiddle
I'm looking to create a table of data (see "Output Table") from the below JSON. I can't seem to get to the "final mile". Can someone show me the way to properly handle the parsing of the arrays into the desired output table?
Thanks! Russ
Desired Output Table
Output I am getting
declare #json nvarchar(max) =
'{
"totalCount": 1,
"nextPageKey": null,
"result": [
{
"metricId": "builtin:host.cpu.usage",
"data": [
{
"dimensions": [
"HOST-CCCC3F95D7CE56"
],
"dimensionMap": {
"dt.entity.host": "HOST-CCCC3F95D7CE56"
},
"timestamps": [
1612634400000,
1612645200000,
1612656000000
],
"values": [
0.37900028935185187,
0.3709309895833333,
0.5088975694444444
]
}
]
}
]
}'
Select TableA.totalCount, TableResult.metricId,
TableDim.*
FROM OPENJSON(#json)
WITH(
totalCount int,
result NVARCHAR(MAX) as JSON
) as TableA
CROSS APPLY OPENJSON(TableA.result)
WITH(
metricId VARCHAR(100),
data NVARCHAR(MAX) as JSON
)TableResult
CROSS APPLY OPENJSON(TableResult.data)
WITH(
dimensions NVARCHAR(MAX) as JSON,
timestamps NVARCHAR(MAX) as JSON,
[values] NVARCHAR(MAX) as JSON
)TableDim
Hard to know what the correlation is between timestamps and values, but I've assumed it's by array index.
Is dimensions always a single value in the array? I have assumed so.
You then need to use OPENJSON (and no WITH block) to break out the two arrays, and join them together on index, which is supplied in key:
Select TableA.totalCount, TableResult.metricId,
TableDim.dimensions, Vals.*
FROM OPENJSON(#json)
WITH(
totalCount int,
result NVARCHAR(MAX) as JSON
) as TableA
CROSS APPLY OPENJSON(TableA.result)
WITH(
metricId VARCHAR(100),
data NVARCHAR(MAX) as JSON
)TableResult
CROSS APPLY OPENJSON(TableResult.data)
WITH(
dimensions NVARCHAR(MAX) '$.dimensions[0]',
timestamps NVARCHAR(MAX) as JSON,
[values] NVARCHAR(MAX) as JSON
)TableDim
CROSS APPLY (
SELECT tm.value AS Timestamp, v.value AS Value
FROM OPENJSON(TableDim.timestamps) tm
JOIN OPENJSON(TableDim.[values]) v ON v.[key] = tm.[key]
) Vals
We recently upgraded our backend DB from SQL Server 2012 to SQL Server 2016 which I realized supports JSON objects. One of our web services return data in the below format, and I am trying to consume it directly using OPENJSON function.
{
"RESULT_1": {
"columns": ["col1", "col2", "col3", "col4"],
"data": [
["0", null, "12345", "other"],
["1", "a", "54321", "MA"],
["0", null, "76543", "RI"]
]
}
}
I want to make sure that I read the column names from the "columns section" and make sure that the correct data is read and pushed in SQL Server 2016.
DECLARE #Json_Array2 nvarchar(max) = '{
"RESULT_1": {
"columns": ["col1", "col2", "col3", "col4"],
"data": [
["0", null, "12345", "other"],
["1", "a", "54321", "MA"],
["0", null, "76543", "RI"]
]
} }';
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.columns')
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.data')
With above statements, I am able to extract the columns and the data array. Would it be possible to dump this data in a flat table (already existing) with the same column names?
I am able to see all the values of one particular row by:
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.data[0]')
key value
0 0
1 NULL
2 12345
3 other
Any pointers are appreciated.
Thank you
If I understand correctly you are trying to extract all elements from the "data" array
Col1 Col2 Col3 Col4
0 NULL 12345 other
1 a 54321 MA
0 NULL 76543 RI
Suppose your Json Structure will not change you can achieve that using the following query:
SET NOCOUNT ON
IF OBJECT_ID ('tempdb..##ToPvt') IS NOT NULL DROP TABLE ##ToPvt
DECLARE #Cmd NVARCHAR(MAX)=''
DECLARE #Table TABLE (Col1 nvarchar(100), Col2 nvarchar(100), Col3 nvarchar(100) , Col4 nvarchar(100))
DECLARE #Json_Array2 nvarchar(max) = '{
"RESULT_1": {
"columns": ["col1", "col2", "col3", "col4"],
"data": [
["0", null, "12345", "other"],
["1", "a", "54321", "MA"],
["0", null, "76543", "RI"]
]
} }';
;WITH Cols ([Key], [Value]) as
(
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.columns')
)
, [Rows] as
(
SELECT ROW_NUMBER () OVER (ORDER BY [Key]) Seq, [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.data')
)
,ToPvt as
(
SELECT c.[Key]+1 Cols, x.Value , 'col'+CONVERT(VARCHAR(10),ROW_NUMBER () OVER (PARTITION BY c.Value ORDER BY t.[Key])) Seq
FROM [Rows] t
INNER JOIN Cols C
ON t.[key] = c.[key]
CROSS APPLY OPENJSON(t.value) X
)
SELECT *
INTO ##ToPvt
FROM ToPvt
;WITH Final (Cmd) as
(
SELECT DISTINCT 'SELECT [col1], [col2], [col3],[col4] FROM ##ToPvt
PIVOT
(
MAX([Value]) FOR Seq IN ([col1], [col2], [col3],[col4])
) T
WHERE Cols = '+CONVERT(VARCHAR(10),Cols)+'
;'
FROM ##ToPvt
)
SELECT #Cmd += Cmd
FROM Final
INSERT INTO #Table
EXEC sp_executesql #Cmd
SELECT *
FROM #Table