SQL JSON query to extract an object - sql

I think the problem is because I have hard brackets [] in the 'groups' object.
JSON:
declare #json nvarchar(max) = N'{ "agents": [ {
"id": 9544321,
"uuid":"xxxx-xxx-xxxx",
"groups": [
{
"name": "GROUP NAME HERE",
"id": 123456
}
],
"support": true
}]}'
What I'm trying to get to is:
id
uuid
group name
group id
9544321
xxxx-xxx-xxxx
GROUP NAME HERE
123456
And then if there is a second group specified in the 'groups' object that'd be two rows. etc
This is my code so far, but it just leaves the [group name] and [group id] columns blank. I've also tried a cross apply and that didn't work (same result).
select *
from openjson(#json, '$.agents')
with (
id int '$.id',
uuid varchar(60) '$.uuid',
groups nvarchar(max) '$.groups' as json
)
outer apply openjson (groups)
with ([group name] nvarchar(max) '$',
[group id] int '$'
)

Try this:
select *
from openjson(#json, '$.agents')
with (
id int '$.id',
uuid varchar(60) '$.uuid',
groups nvarchar(max) '$.groups' as json
)
outer apply openjson (groups, '$')
with ([name] nvarchar(max),
[id] int
)
Did you find the difference? You have placed the value 'Group Name' which is the value, instead of keys in json.

#BeckyG, you're almost there. Please, pay attention to lines 29 and 30:
DECLARE #json NVARCHAR(MAX) = N'{ "agents": [ {
"id": 9544321,
"uuid":"xxxx-xxx-xxxx",
"groups": [
{
"name": "GROUP NAME HERE",
"id": 123456
},
{
"name": "GROUP NAME HERE 2",
"id": 1234567
}
],
"support": true
}]}';
SELECT agents.id,
agents.uuid,
groups.name [group name],
groups.id [group id]
FROM OPENJSON(#json, '$.agents')
WITH (
id INT '$.id',
uuid VARCHAR(60) '$.uuid',
groups NVARCHAR(MAX) '$.groups' AS JSON
) AS agents
OUTER APPLY OPENJSON (agents.groups)
WITH (
[name] NVARCHAR(MAX) '$.name',
[id] INT '$.id'
) AS groups;
Happy coding!

Related

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

Using multiple Cross Joins with JSON seems to slow my query right down and never completes

I have the following JSON:
[
{
"UserDetails": [
{
"UserName": "User1",
"UserDateOfBirth": "06/11/89",
"UserID": "12345",
"NotesDay1": [
{
"NoteID": "a287fcc4",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-06T00:19:14"
},
{
"NoteID": "4a48385a",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-06T02:19:59"
},
{
"NoteID": "ddb6bc52",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-06T04:14:50"
}
]
},
{
"UserName": "User2",
"UserDateOfBirth": "05/08/99",
"UserID": "23456",
"NotesDay1": [],
"NotesDay2": [
{
"NoteID": "62cf5478",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T01:00:48"
},
{
"NoteID": "7f864ef4",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T01:00:48"
},
{
"NoteID": "db1a0af0",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T06:28:02"
}
],
"NotesDay3": [
{
"NoteID": "2ae6b923",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T06:28:02"
}
],
"NotesDay4": [],
"NotesDay5": [],
"NotesDay6": [],
"NotesDay7": []
}
]
}
]
My current SQL query to import this is set up as below:
SELECT j2.UserID, j3.NoteID1, j4.NoteID2, j5.NoteID3, j6.NoteID4, j7.NoteID5, j8.NoteID6, j9.NoteID7
INTO [UserDayNotes]
FROM OPENJSON(#JSON)
WITH
(
UserDetails nvarchar(max) '$.UserDetails' as JSON
) j1
CROSS APPLY OPENJSON(j1.UserDetails) WITH
(
UserID nvarchar(100) '$.UserID',
NotesDay1 nvarchar(max) '$.NotesDay1' as JSON,
NotesDay2 nvarchar(max) '$.NotesDay2' as JSON,
NotesDay3 nvarchar(max) '$.NotesDay3' as JSON,
NotesDay4 nvarchar(max) '$.NotesDay4' as JSON,
NotesDay5 nvarchar(max) '$.NotesDay5' as JSON,
NotesDay6 nvarchar(max) '$.NotesDay6' as JSON,
NotesDay7 nvarchar(max) '$.NotesDay7' as JSON
) j2
CROSS APPLY OPENJSON(j2.NotesDay1) WITH
(
NoteID1 nvarchar(100) '$.NoteID'
) j3
CROSS APPLY OPENJSON(j2.CareNotesDay2) WITH
(
NoteID2 nvarchar(100) '$.NoteID'
) j4
CROSS APPLY OPENJSON(j2.CareNotesDay3) WITH
(
NoteID3 nvarchar(100) '$.NoteID'
) j5
CROSS APPLY OPENJSON(j2.CareNotesDay4) WITH
(
NoteID4 nvarchar(100) '$.NoteID'
) j6
CROSS APPLY OPENJSON(j2.CareNotesDay5) WITH
(
NoteID5 nvarchar(100) '$.NoteID'
) j7
CROSS APPLY OPENJSON(j2.CareNotesDay6) WITH
(
NoteID6 nvarchar(100) '$.NoteID'
) j8
CROSS APPLY OPENJSON(j2.CareNotesDay7) WITH
(
NoteID3 nvarchar(100) '$.NoteID'
) j9
If I run the query as it is, then it runs forever and ever and never completes. If I comment out all but j2.UserID, j3.NoteID1 and j4.NoteID2, then the query runs more or less instantly. I'm assuming this is something to do with the number of cross apply items I have, but my experience and knowledge of this side of SQL is not great, and I could really use some help.
After discussions below, I've realised I could have multiple instances of Day1, Day 2 etc and so a more realistic desired output would be below:
UserID
DayNumber
NoteID
User1
1
a287fcc4
User1
1
4a48385a
User1
1
ddb6bc52
User2
2
62cf5478
User2
2
7f864ef4
User2
2
db1a0af0
User2
3
2ae6b923
(Good lord, that table took some doing!)
The data inside each NotesDayX object is a repeat of information held elsewhere, so as long as I have the NoteID then I can dispense with the other info contained within the JSON.
Thanks in advance.
You could union all the Notes arrays together.
Furthermore, it's unclear if the outer array always has only a single inner object, if so then we can use $[0] and skip the first OPENJSON
SELECT
j1.UserID,
j2.DayNumber,
j2.NoteID
INTO [UserDayNotes]
FROM OPENJSON(#JSON, '$[0].UserDetails')
WITH
(
UserID nvarchar(100),
NotesDay1 nvarchar(max) as JSON,
NotesDay2 nvarchar(max) as JSON,
NotesDay3 nvarchar(max) as JSON,
NotesDay4 nvarchar(max) as JSON,
NotesDay5 nvarchar(max) as JSON,
NotesDay6 nvarchar(max) as JSON,
NotesDay7 nvarchar(max) as JSON
) j1
CROSS APPLY (
SELECT 1 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay1) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 2 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay2) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 3 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay3) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 4 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay4) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 5 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay5) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 6 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay6) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 7 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay7) WITH
(
NoteID nvarchar(100)
) j2
) j2;
..if the json structure is slightly different and if there can be only one object in the userdetails and notesdayX arrays …fiddle:
declare #j nvarchar(max) =N'
[
{"UserDetails":[
{"UserID":"User1",
"NotesDay1":[{"NoteID":"12345"}],
"NotesDay2":[],
"NotesDay3":[],
"NotesDay4":[{"NoteID":"23456"}],
"NotesDay5":[],
"NotesDay6":[{"NoteID":"34567"}],
"NotesDay7":[{"NoteID":"45678"}]
}
]},
{"UserDetails":[
{"UserID":"User2",
"NotesDay1":[{"NoteID":"54321"}],
"NotesDay2":[{"NoteID":"65432"}],
"NotesDay3":[],
"NotesDay4":[{"NoteID":"76543"}],
"NotesDay5":[],
"NotesDay6":[],
"NotesDay7":[{"NoteID":"87654"}]
}
]}
]';
select *
from openjson(#j)
with
(
userid nvarchar(100) '$.UserDetails[0].UserID',
notesday1 nvarchar(10) '$.UserDetails[0].NotesDay1[0].NoteID',
notesday4 nvarchar(10) '$.UserDetails[0].NotesDay4[0].NoteID',
notesday7 nvarchar(10) '$.UserDetails[0].NotesDay7[0].NoteID'
);

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

Create table from openjson(#json) results Azure SQL

I am trying to make a table out of the [key] row values from a
select * from openjson(#json) statement. The openjson(#json) statement gives me results that contains 53 [key] row values, here's a small snippet:
[key] [value] [type]
_id 5b05390c5d222f0059209918 1
ean 65485555 1
name NULL 0
holder {"_id":"5b0538355d222f00585db6f1","name":"***... 5
root {"_id":"5b05390c5d222f005920990a","holder":{"_id":"5b0538885... 5
assigner {"_id":"5b0538885d222f00570aca19","name":"***... 5
created 2018-05-23T09:49:00+0000 1
children [] 4
address 1
timezone Etc/GMT-1 1
I want a table that look something like this:
table1
[_id] [ean] [name] [holder] [etc...]
5b05390c5d222f0059209918 65485555 NULL {"_id":"5b0538355d222...}
I also want to be able to insert values from another JSON into the same table
insert into table1 ()
select [value] from openjson(#json2)
Thank you!
Just add a WITH clause to your OPENJSON query.
See OPENJSON, eg:
DECLARE #json NVARCHAR(MAX) = N'[
{
"Order": {
"Number":"SO43659",
"Date":"2011-05-31T00:00:00"
},
"AccountNumber":"AW29825",
"Item": {
"Price":2024.9940,
"Quantity":1
}
},
{
"Order": {
"Number":"SO43661",
"Date":"2011-06-01T00:00:00"
},
"AccountNumber":"AW73565",
"Item": {
"Price":2024.9940,
"Quantity":3
}
}
]'
SELECT *
FROM OPENJSON ( #json )
WITH (
Number varchar(200) '$.Order.Number',
Date datetime '$.Order.Date',
Customer varchar(200) '$.AccountNumber',
Quantity int '$.Item.Quantity',
[Order] nvarchar(MAX) AS JSON
)