SQL Query on Json object inside multiple JSON objects - sql

I have the below Json string. I need to write a query to get the TP records. Without providing the index value, we need get the result.
{
"S": [
{
"Name": "Project1",
"SP": [
{
"ID": 1,
"Name": "Test1",
"TP": [
{
"TID": 11,
"TName": "TT1",
},
{
"TID": 12,
"TName": "TT2",
},
]
},
{
"ID": 2,
"Name": "Test2",
"TP": [
{
"TID": 13,
"TName": "TT3",
},
{
"TID": 14,
"TName": "TT4",
},
]
},
]}]}
How do I query to get the TP values.
Expected Result:
TID TName
11 TT1
12 TT2
13 TT3
14 TT4

You can use OPENJSON function containing WITH Clause added as many CROSS APPLY Clause as upto see all sub-arrays :
SELECT S3.TID, S3.TName
FROM tab
CROSS APPLY OPENJSON(JsonData)
WITH ( S nvarchar(max) '$.S' AS JSON) AS S0
CROSS APPLY OPENJSON (S0.S)
WITH (
SP nvarchar(max) '$.SP' AS JSON ) S1
CROSS APPLY OPENJSON (S1.SP)
WITH (
TP nvarchar(max) '$.TP' AS JSON ) S2
CROSS APPLY OPENJSON (S2.TP)
WITH (
TID nvarchar(500) '$.TID',
TName nvarchar(500) '$.TName' ) S3
Demo
Update : If the first array S is fixed to contain only one item, we can reduce one-step as
SELECT S3.TID, S3.TName
FROM tab
CROSS APPLY OPENJSON(JsonData)
WITH (
SP nvarchar(max) '$.S[0].SP' AS JSON ) S1
CROSS APPLY OPENJSON (S1.SP)
WITH (
TP nvarchar(max) '$.TP' AS JSON ) S2
CROSS APPLY OPENJSON (S2.TP)
WITH (
TID nvarchar(500) '$.TID',
TName nvarchar(500) '$.TName' ) S3
Demo

Related

SQL OPENJSON get only first element

I'm trying to get data from only the first element in the JSON string because the first element will always be the newest. I have tried a few things with no luck. Maybe someone here can point me in the right direction.
This is the JSON string:
[
{
"wd:Transaction_Log_Entry": [
{
"wd:Transaction_Log_Reference": {
"#wd:Descriptor": "Rescind of End Contract: XXXX (Rescinded)",
"wd:ID": {
"#wd:type": "WID",
"#text": "fb27bafef89b101b5bf865947b420000"
}
},
"wd:Transaction_Log_Data": {
"wd:Transaction_Log_Description": "Rescind of End Contract: XXXX (Rescinded)",
"wd:Transaction_Effective_Moment": "2023-01-18T09:00:00+01:00",
"wd:Transaction_Entry_Moment": "2023-01-19T10:49:00.868+01:00",
"wd:Is_Rescind_Or_Rescinded": "1",
"wd:Is_Correction_Or_Corrected": "0"
}
},
{
"wd:Transaction_Log_Reference": {
"#wd:Descriptor": "End Contract: XXXX (Rescinded)",
"wd:ID": {
"#wd:type": "WID",
"#text": "a4a0fd2c2df8101bd1c6bde5f5710000"
}
},
"wd:Transaction_Log_Data": {
"wd:Transaction_Log_Description": "End Contract: XXXX (Rescinded)",
"wd:Transaction_Effective_Moment": "2023-01-18T09:00:00+01:00",
"wd:Transaction_Entry_Moment": "2023-01-18T12:41:43.867+01:00",
"wd:Is_Rescind_Or_Rescinded": "1",
"wd:Is_Correction_Or_Corrected": "0"
}
}
]
}
]
And my SQL query - I'm selecting the JSON string from a table that has the column name 'Transaction_Log_Entry_Data'
SELECT Effective_Moment, Entry_Moment
FROM [dbo].[Daily_And_Future_Terminations_Transaction_Log_Source]
CROSS APPLY OPENJSON (Transaction_Log_Entry_Data, '$[0]."wd:Transaction_Log_Entry"')
WITH (
Effective_Moment NVARCHAR(50) '$."wd:Transaction_Log_Data"."wd:Transaction_Effective_Moment"',
Entry_Moment NVARCHAR(50) '$."wd:Transaction_Log_Data"."wd:Transaction_Entry_Moment"'
)
And my results is 2 rows and I only want data from the first element:
Best regards
Ole
You have an arry in an array, so you must write.
JSOn is an interesting data structure, but you need a lot of experience with it
SELECT Effective_Moment, Entry_Moment
FROM [Daily_And_Future_Terminations_Transaction_Log_Source]
CROSS APPLY OPENJSON (Transaction_Log_Entry_Data, '$[0]."wd:Transaction_Log_Entry"[0]')
WITH (
Effective_Moment NVARCHAR(50) '$."wd:Transaction_Log_Data"."wd:Transaction_Effective_Moment"',
Entry_Moment NVARCHAR(50) '$."wd:Transaction_Log_Data"."wd:Transaction_Entry_Moment"'
)
Effective_Moment
Entry_Moment
2023-01-18T09:00:00+01:00
2023-01-19T10:49:00.868+01:00
fiddle
SELECT TOP 1 Effective_Moment, Entry_Moment
FROM [Daily_And_Future_Terminations_Transaction_Log_Source]
CROSS APPLY OPENJSON (Transaction_Log_Entry_Data, '$[0]."wd:Transaction_Log_Entry"')
WITH (
Effective_Moment NVARCHAR(50) '$."wd:Transaction_Log_Data"."wd:Transaction_Effective_Moment"',
Entry_Moment NVARCHAR(50) '$."wd:Transaction_Log_Data"."wd:Transaction_Entry_Moment"'
)
ORDEr By Entry_Moment DESC
Effective_Moment
Entry_Moment
2023-01-18T09:00:00+01:00
2023-01-19T10:49:00.868+01:00
fiddle

How to flatten nested array from JSON in SQL Server

I am trying to flatten nested array from JSON in SQL Server, using the code below, but without success.
Used JSON
'{
"shipmentDetails": {
"shipmentId": "JHVJD5627278788"
},
"shipmentStops": [
{
"stopSequence": 1,
"orderReferenceNumbers": [
"2120549020", "test"
]
},
{
"stopSequence": 2,
"orderReferenceNumbers": [
"2120549020", "2120549002"
]
}
]
}'
DECLARE #Step AS NVARCHAR(max) = N'Variables declaration';
DECLARE #JSON1 AS NVARCHAR(MAX);
SET #JSON1 = '{
"shipmentDetails": {
"shipmentId": "JHVJD5627278788"
},
"shipmentStops": [
{
"stopSequence": 1,
"orderReferenceNumbers": [
"2120549020", "test"
]
},
{
"stopSequence": 2,
"orderReferenceNumbers": [
"2120549020", "2120549002"
]
}
]
}'
IF OBJECT_ID('JSONPO2') IS NOT NULL
DROP TABLE JSONPO2
SET #Step = N'JSON data parsing and loading into JSONPO2 temp table'
SELECT DISTINCT ShipDetails.shipmentId AS shipmentId
,ShipmentStops.stopSequence AS stopSequence
,ShipmentStops.orderReferenceNumbers AS orderReferenceNumbers
INTO JSONPO2
FROM OPENJSON(#JSON1) WITH (
shipmentDetails NVARCHAR(MAX) AS JSON
,shipmentStops NVARCHAR(MAX) AS JSON
) AS [Data]
CROSS APPLY OPENJSON(shipmentDetails) WITH (shipmentId NVARCHAR(20)) AS ShipDetails
CROSS APPLY OPENJSON(shipmentStops) WITH (
stopSequence INT
,orderReferenceNumbers NVARCHAR(MAX) AS JSON
) AS ShipmentStops
CROSS APPLY OPENJSON(orderReferenceNumbers) WITH (orderReferenceNumbers VARCHAR(max))
AS orderReferenceNumbers
SELECT *
FROM JSONPO2
From the above code, I receive only two rows with a strange array
shipmentId
stopSequence
orderReferenceNumbers
JHVJD5627278788
1
[ "2120549020", "test" ]
JHVJD5627278788
2
[ "2120549020", "2120549002" ]
How to change the code to parse nested arrays and have four rows like below?
shipmentId
stopSequence
orderReferenceNumbers
JHVJD5627278788
1
2120549020
JHVJD5627278788
1
test
JHVJD5627278788
2
2120549020
JHVJD5627278788
2
2120549002
Appreciate any help :)
Your issue is when trying to expand the array using the WITH clause:
CROSS APPLY OPENJSON(orderReferenceNumbers)
WITH (orderReferenceNumbers VARCHAR(max)) AS orderReferenceNumbers
The JSON you are opening though has no property "orderReferenceNumbers", it is simply:
["2120549020", "test"]
So this is returning NULL. You'd see this in your select if you were selecting orderReferenceNumbers.orderReferenceNumbers rather than ShipmentStops.orderReferenceNumbers.
You don't need to use WITH if you are opening a simple JSON array of primitive types. The following query will return the output you are after:
DECLARE #JSON1 AS NVARCHAR(MAX) = N'{
"shipmentDetails": {
"shipmentId": "JHVJD5627278788"
},
"shipmentStops": [
{
"stopSequence": 1,
"orderReferenceNumbers": [
"2120549020", "test"
]
},
{
"stopSequence": 2,
"orderReferenceNumbers": [
"2120549020", "2120549002"
]
}
]
}';
SELECT sd.shipmentId,
ss.stopSequence,
orderReferenceNumber = orn.Value
FROM OPENJSON(#JSON1)
WITH(shipmentDetails NVARCHAR(MAX) AS JSON, shipmentStops NVARCHAR(MAX) AS JSON) AS d
CROSS APPLY OPENJSON(d.shipmentDetails)
WITH(shipmentId NVARCHAR(20)) AS sd
CROSS APPLY OPENJSON(d.shipmentStops)
WITH(stopSequence INT, orderReferenceNumbers NVARCHAR(MAX) AS JSON) AS ss
CROSS APPLY OPENJSON(orderReferenceNumbers) AS orn;
Example on db<>fiddle
As an aside, if you will only ever have one shipmentId in the JSON (which would make sense otherwise you'd end up with cross joins) you can simplify this slightly, and remove one of the OPENJSON()s:
SELECT d.shipmentId,
ss.stopSequence,
orderReferenceNumber = orn.Value
FROM OPENJSON(#JSON1)
WITH(ShipmentId NVARCHAR(20) '$.shipmentDetails.shipmentId',
shipmentStops NVARCHAR(MAX) AS JSON) AS d
CROSS APPLY OPENJSON(d.shipmentStops)
WITH(stopSequence INT, orderReferenceNumbers NVARCHAR(MAX) AS JSON) AS ss
CROSS APPLY OPENJSON(ss.orderReferenceNumbers) AS orn;

Extract a JSON array items to a single column separated with comma

Struggling to find an answer to the below JSON problem. I would like to display the entire SKU/Quantity list in the "shipmentItems" array to their respective column with a comma-separated value. My example below only allows me to display the first SKU/quantity from the array but, my goal is to get all listed in the columns with comma-separated.
JSON example:
{"shipments": [
{
"shipmentId": 100003768,
"orderNumber": "9648219086",
"shipDate": "2021-10-28",
"serviceCode": "ups_ground",
"shipmentItems": [
{
"orderItemId": 1464643208,
"lineItemKey": "10322938560608",
"sku": "SCPXTSS-BAG-06",
"name": "SCOOP-PLATE-06 (1000ml)",
"weight": {
"value": 0,
"units": "ounces",
"WeightUnits": 1
},
"quantity": 1,
"unitPrice": 0,
"taxAmount": null
},
{
"orderItemId": 1464643207,
"lineItemKey": "10322938527840",
"sku": "SCPZRTS-TRAY-01",
"name": "Beef: Tray 3 (Fill 004)<br>",
"weight": {
"value": 60,
"units": "ounces",
"WeightUnits": 1
},
"quantity": 1,
"unitPrice": 102.72,
"taxAmount": null
}
],
"labelData": null,
"formData": null
}
]
}
SQL query I'm using:
DECLARE #JSON varchar(max)
SELECT #JSON = BulkColumn
FROM OPENROWSET (BULK 'C:\Users\XPS-LT\json\today\shipments_20211031.json', SINGLE_CLOB)
IMPORT
SELECT *
FROM OPENJSON (#JSON, '$.shipments')
WITH
(
[shipmentId] bigint,
[orderNumber] nvarchar(60),
[shipDate] date,
[serviceCode] nvarchar(30),
[sku] nvarchar(MAX) N'$.shipmentItems[0].sku',
[quantity] int N'$.shipmentItems[0].quantity'
)
;
The "shipmentItems" part of the input JSON is an array, so you need an AS JSON clause in the first explicit schema and an additional OPENJSON() call:
DECLARE #json nvarchar(max)
...
SELECT
j.[shipmentId], j.[orderNumber], j.[shipDate], j.[serviceCode],
a.[sku], a.[quantity]
FROM OPENJSON (#json, '$.shipments') WITH (
[shipmentId] bigint,
[orderNumber] nvarchar(60),
[shipDate] date,
[serviceCode] nvarchar(30),
[shipmentItems] nvarchar(max) AS JSON
) j
OUTER APPLY (
SELECT
STRING_AGG([sku], ',') WITHIN GROUP (ORDER BY [orderItemId]),
STRING_AGG([quantity], ',') WITHIN GROUP (ORDER BY [orderItemId])
FROM OPENJSON (j.shipmentItems) WITH (
[orderItemId] int '$.orderItemId',
[sku] nvarchar(max) '$.sku',
[quantity] int N'$.quantity'
)
) a ([sku], [quantity])
Result:
shipmentId orderNumber shipDate serviceCode sku quantity
100003768 9648219086 2021-10-28 ups_ground SCPZRTS-TRAY-01,SCPXTSS-BAG-06 1,1

SQL Query to get the json array values by comma separated

I have the below Json object. I need to get the task names by comma (,) separated.
{
"Model": [
{
"ModelName": "Test Model",
"Object": [
{
"ID": 1,
"Name": "ABC",
"Task" : [
{
TaskID : 1222,
Name: "TaskA"
},
{
TaskID : 154,
Name: "TaskB"
}
]
},
{
"ID": 11,
"Name": "ABCD",
"Task" : [
{
TaskID : 222,
Name: "TaskX"
},
{
TaskID : 234,
Name: "TaskY"
}
]
},
]
}]}
The expected Output should be in the below table. I need the task names should be comma separated.
ModelName ObjectID ObjectName TaskName
Test Model 1 ABC TaskA, TaskB
Test Model 11 ABCD TaskX, TaskY
I tried the below query. But I don't know how to group Task names.
SELECT S1.ModelName,
S2.ID AS ObjectID,
S2.Name AS ObjectName,
S3.TaskName
FROM TableA
CROSS APPLY OPENJSON(JsonData)
WITH (Model NVARCHAR(MAX) '$.Model[0]' AS JSON) S1
CROSS APPLY OPENJSON (S1.Model)
WITH (Object NVARCHAR(MAX) '$.Object' AS JSON,
ID INT '$.ID',
Name NVARCHAR(250) '$.Name') S2
CROSS APPLY OPENJSON (S2.Object)
WITH (Task NVARCHAR(MAX) '$.Task' AS JSON ,
TaskName NVARCHAR(MAX) '$.TaskName') S3
Corrected the json to a valid format and here is the SQL query for your desired output. The below query compiles and runs well in Oracle Compiler
SELECT * FROM JSON_TABLE(
'{"Model":[{"ModelName":"Test Model","Object":[{"ID":1,"Name":"ABC","Task":[{"TaskID":1222,"Name":"TaskA"},{"TaskID":154,"Name":"TaskB"}]},{"ID":11,"Name":"ABCD","Task":[{"TaskID":222,"Name":"TaskX"},{"TaskID":234,"Name":"TaskY"}]}]}]}',
'$.Model[*]'
COLUMNS (
-- L_MODEL_ROWNUM FOR ORDINALITY,
L_MODEL_NAME VARCHAR2(10) PATH '$.ModelName',
NESTED PATH '$.Object[*]' COLUMNS (
--L_OBJECT_ROWNUM FOR ORDINALITY,
L_OBJECT_ID NUMBER PATH '$.ID',
L_OBJECT_NAME VARCHAR2(10) PATH '$.Name',
L_TASK_NAME VARCHAR2(100) FORMAT JSON WITH WRAPPER PATH '$.Task[*].Name'
)
)
)
Here is the query which runs on SQL Server 2019,
DECLARE #JSONDATA NVARCHAR(MAX);
SET
#JSONDATA = N'{"Model":[{"ModelName":"Test Model","Object":[{"ID":1,"Name":"ABC","Task":[{"TaskID":1222,"Name":"TaskA"},{"TaskID":154,"Name":"TaskB"}]},{"ID":11,"Name":"ABCD","Task":[{"TaskID":222,"Name":"TaskX"},{"TaskID":234,"Name":"TaskY"}]}]}]}';
WITH TASK AS
(
SELECT
MODEL,
ID,
NAME,
TASK_NAME
FROM
OPENJSON(#JSONDATA) WITH (MODELS NVARCHAR(MAX) '$.Model' AS JSON) CROSS APPLY OPENJSON(MODELS) WITH (MODEL NVARCHAR(80) '$.ModelName', OBJECTS NVARCHAR(MAX) '$.Object' AS JSON) CROSS APPLY OPENJSON(OBJECTS ) WITH (ID INT '$.ID', NAME NVARCHAR(250) '$.Name', TASKS NVARCHAR(MAX) '$.Task' AS JSON ) CROSS APPLY OPENJSON (TASKS) WITH (TASK_NAME NVARCHAR(80) '$.Name')
)
SELECT DISTINCT
MODEL AS MODELNAME,
ID AS OBJECTID,
NAME AS OBJECTNAME,
STUFF((
SELECT
',' + [TASK_NAME]
FROM
TASK T1
WHERE
T1.[ID] = T2.[ID] FOR XML PATH('')), 1, 1, '') AS TASKNAME
FROM
TASK T2;

How to write a select query to get the index value from Json object

I have the below JSON object. I need to write a select query to get the index values of Object JSON array. Kind of getting the sequence value.
{
"Model": [
{
"ModelName": "Test Model",
"Object": [
{
"ID": 1,
"Name": "ABC",
},
{
"ID": 11,
"Name": "ABCD",
},
{
"ID": 15,
"Name": "ABCDE",
},
]
}]}
Expected Output:
Index_Value
1
2
3
If I understand the question correctly and you want to get the index of the items in the Object JSON array, you need to use OPENJSON() with default schema. The result is a table with columns key, value and type and in case of JSON array, the key column holds the index of each item in the array (0-based):
JSON:
DECLARE #json nvarchar(max) = N'{
"Model":[
{
"ModelName":"Test Model",
"Object":[
{
"ID":1,
"Name":"ABC"
},
{
"ID":11,
"Name":"ABCD"
},
{
"ID":15,
"Name":"ABCDE"
}
]
}
]
}'
Statement:
SELECT CONVERT(int, j2.[key]) + 1 AS item_id
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value], '$.Object') j2
But if you want to get the values of the ID keys in the Object JSON array, the statement is different:
SELECT j2.ID
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value], '$.Object') WITH (
ID int '$.ID'
) j2
Note, that you need two OPENJSON() calls, because the input JSON has nested array structure. Of course, if Model JSON array has always one item, you may simplify the statement using an appropriate path:
SELECT CONVERT(int, [key]) + 1 AS item_id
FROM OPENJSON (#json, '$.Model[0].Object')
Finally, to get index, ID and Name, you should use the following statement, which assumes, that $.Model JSON array has more than one item and defines ID and Name columns with the appropraite data types:
SELECT
CONVERT(int, j2.[key]) + 1 AS ItemID,
j3.ID, j3.Name
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value], '$.Object') j2
CROSS APPLY OPENJSON(j2.[value], '$') WITH (
ID int '$.ID',
Name varchar(50) '$.Name'
) j3
DECLARE #json nvarchar(max) = N'{
"Model":[
{
"ModelName":"Test Model",
"Object":[
{
"ID":1,
"Name":"ABC"
},
{
"ID":11,
"Name":"ABCD"
},
{
"ID":15,
"Name":"ABCDE"
}
]
}
]
}'
declare #i int=0;
SELECT
j2.ID, j2.Name
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value],concat('$.Object[',#i,']')) WITH (
ID i`enter code here`nt '$.ID', Name varchar(100) '$.Name'
) j2
Results:-
ID
Name
11
ABCD
you can select the key columns in select clause no need to mention in with of crossjoin.
SELECT
distinct t.id,
JSON_VALUE(AttsData.[value], '$.address') as address,
JSON_VALUE(AttsData.[value], '$.name') as name,
JSON_VALUE(AttsData.[value], '$.owner_name') as owner_name,
JSON_VALUE(AttsData.[value], '$.project') as project
,CONVERT(int, AttsData.[key]) index_id
FROM mytablewithjsonfeild t
CROSS APPLY OPENJSON (t."jsonfeild",N'$.parentkey') as AttsData
Above query, from the table I have cross joined the JSON field. and in select statement i have taken the specific keys.
and CONVERT(int, AttsData.[key]) to get the index of the elements