How do I parse nested JSON-objects in SQL? - sql

I have a string of JSON, returned by an API, that looks something like this:
{
"data": {
"transactions": {
"edges": [
{
"node": {
"text": "debet",
"invoiceAmount": "1.0000"
}
},
{
"node": {
"text": "kredit",
"invoiceAmount": "-1.0000"
}
}
]
}
}
}
It is valid JSON, however the only way that I am able to parse in sql is by manipulating the string first. Like this:
[
{
"node": {
"text": "debet",
"invoiceAmount": "1.0000"
}
},
{
"node": {
"text": "kredit",
"invoiceAmount": "-1.0000"
}
}
]
E.g. below. How do I achieve this without manipulating the string?
DECLARE #json NVARCHAR(MAX);
SET #json = N'[{"node":{"text":"debet","invoiceAmount":"1.0000"}},{"node":{"text":"kredit","invoiceAmount":"-1.0000"}}]';
SELECT *
FROM OPENJSON(#json)
WITH (
text NVARCHAR(50) '$.node.text',
invoiceAmount MONEY '$.node.surname'
)
I tried $.data.transactions.edges.node.text. SQL returns NULL

You can use
SELECT *
FROM OPENJSON(JSON_QUERY(#json, '$.data.transactions.edges'))
WITH (
text VARCHAR(100) '$.node.text',
invoiceAmount DECIMAL(10,4) '$.node.invoiceAmount'
)
to get the desired values out of your original string.
(DB Fiddle)
The JSON_QUERY first extracts the array and then that is expanded out with OPENJSON.

Related

How to create a SQL statement to produce nested JSON from variables?

I have managed to create SQL for the individual nodes, but cannot deduce how to refine the statement to include or merge both outputs.
DECLARE
#FulfillmentOrderId BIGINT = 0,
#NotifyCustomer BIT = 1,
#TrackingCompany NVARCHAR(100) = '',
#TrackingNo NVARCHAR(100) = '';
INPUT
SELECT
#NotifyCustomer AS [notify_customer],
#TrackingCompany AS [tracking_info.company],
#TrackingNo AS [tracking_info.number]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
OUTPUT
{
"line_items_by_fulfillment_order": [
{
"fulfillment_order_id": 0
}
]
}
INPUT
SELECT (
SELECT
#FulfillmentOrderId AS [fulfillment_order_id]
FOR JSON PATH
) AS [line_items_by_fulfillment_order]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
OUTPUT
{
"notify_customer": true,
"tracking_info": {
"company": "",
"number": ""
}
}
DESIRED OUTPUT
{
"fulfillment": {
"notify_customer": true,
"tracking_info": {
"company": "",
"number": 0
},
"line_items_by_fulfillment_order": [
{
"fulfillment_order_id": 0
}
]
}
}
You need to build the nested "line_items_by_fulfillment_order" JSON array and change the paths:
SELECT
#NotifyCustomer AS [fulfillment.notify_customer],
#TrackingCompany AS [fulfillment.tracking_info.company],
#TrackingNo AS [fulfillment.tracking_info.number],
(SELECT #FulfillmentOrderId AS fulfillment_order_id FOR JSON PATH) AS [fulfillment.line_items_by_fulfillment_order]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
SQL Server 2022 introduced new JSON features, so the following statement is also an option:
SELECT JSON_OBJECT(
'fulfillment': JSON_OBJECT(
'notify_customer': #NotifyCustomer,
'tracking_info': JSON_OBJECT('company': #TrackingCompany, 'number': #TrackingNo),
'line_items_by_fulfillment_order': JSON_ARRAY(JSON_OBJECT('fulfillment_order_id': #FulfillmentOrderId))
)
)
Result:
{
"fulfillment":{
"notify_customer":true,
"tracking_info":{"company":"","number":""},
"line_items_by_fulfillment_order":[{"fulfillment_order_id":0}]
}
}

SQL Server OPENJSON read nested JSON same key array

I am following the idea from Ed.Schavelev on article 'SQL Server OPENJSON read nested json'. But I need instead of repeating the rows I wanted them (4) to be in the columns. Is this possible?
I have tried as below:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{
"EmployeeScheduleXRefCode":"#DF_10212",
"EmployeeXRefCode":"7274",
"TimeStart":"2022-10-31T05:30:00",
"TimeEnd":"2022-10-31T15:30:00",
"Published":false,
"Breaks":[
],
"Activities":[
],
"Skills":[
],
"LaborMetrics":[
{
"CodeXRefCode":"MEDIUM",
"TypeXRefCode":"ACUITY_LM"
},
{
"CodeXRefCode":"ATA",
"TypeXRefCode":"EMPLOYEE_TYPE_LM"
},
{
"CodeXRefCode":"BM02KR",
"TypeXRefCode":"TEAM_NAME_LM"
},
{
"CodeXRefCode":"AV_LM",
"TypeXRefCode":"JOB_TYPE_LM"
}
],
"Segments":[
]
},
{
"EmployeeScheduleXRefCode":"#DF_10200",
"EmployeeXRefCode":"7269",
"TimeStart":"2022-10-31T05:30:00",
"TimeEnd":"2022-10-31T15:30:00",
"Published":false,
"Breaks":[
],
"Activities":[
],
"Skills":[
],
"LaborMetrics":[
{
"CodeXRefCode":"MEDIUM",
"TypeXRefCode":"ACUITY_LM"
},
{
"CodeXRefCode":"ATA",
"TypeXRefCode":"EMPLOYEE_TYPE_LM"
},
{
"CodeXRefCode":"BM01KR",
"TypeXRefCode":"TEAM_NAME_LM"
},
{
"CodeXRefCode":"AV_LM",
"TypeXRefCode":"JOB_TYPE_LM"
}
],
"Segments":[
]
}
]'
SELECT Shifts.*,LaborMetrics.* FROM
OPENJSON ( #json )
WITH (
EmployeeScheduleXRefCode varchar(200) '$.EmployeeScheduleXRefCode' ,
EmployeeXRefCode varchar(200) '$.EmployeeXRefCode',
TimeStart Datetime '$.TimeStart',
TimeEnd Datetime '$.TimeEnd',
LaborMetrics nvarchar(max) as json
) as Shifts
cross apply openjson (Shifts.LaborMetrics)
with
(
CodeXRefCode nvarchar(100),
TypeXRefCode nvarchar(100)
) as LaborMetrics
But the result is repeating 4 rows and I want them to have them in 4 different columns in a single row.

Advice on using OPENJSON to parse a nested array

I am hoping somebody can help point me in the right direction as Iā€™m trying to parse a json file into sql using OPENJSON. I have a structure which looks like this:
DECLARE #json AS NVARCHAR(MAX) = '
[{
"id": "78",
"Version": {
"Value": "12"
},
"Names": [{
"NameId": {
"Value": "8516365"
},
"id": "328787",
"NameLinkType": {
"Value": "A"
"CommsChains": {
"Value": [[{
"com_primary": {
"Value": "Y"
},
"com_recd": {
"Value": "2020-07-07 00:00:00.000"
},
"com_ack": {
"Value": "2020-07-09 00:00:00.000"
},
}
]]
), },
},
],
}
]'
I am able to parse the majority of the JSON correctly, so for each ID I can return values such as Version or NameId. However, I am unable to return any dates in respect of com_recd or com_ack, which sit under CommsChains [Object] ā€“ Value [Array] ā€“ [0] [Array]
It looks like there are some syntactic errors in your JSON. After having them fixed, I was able to try and find the JSON paths to the date expressions to the date values. This is the SQL:
DECLARE #json AS NVARCHAR(MAX) = '
[{
"id": "78",
"Version": {
"Value": "12"
},
"Names": [{
"NameId": {
"Value": "8516365"
},
"id": "328787",
"NameLinkType": {
"Value": "A",
"CommsChains": {
"Value": [[{
"com_primary": {
"Value": "Y"
},
"com_recd": {
"Value": "2020-07-07 00:00:00.000"
},
"com_ack": {
"Value": "2020-07-09 00:00:00.000"
}
}
]]
}
}
}
]
}
]'
select * from openjson(#json, '$[0].Version');--Value 12 1
select * from openjson(#json, '$[0].Names');
select * from openjson(#json, '$[0].Names[0]');
select * from openjson(#json, '$[0].Names[0].NameLinkType');
select * from openjson(#json, '$[0].Names[0].NameLinkType.CommsChains');
select * from openjson(#json, '$[0].Names[0].NameLinkType.CommsChains.Value');
select * from openjson(#json, '$[0].Names[0].NameLinkType.CommsChains.Value[0]');
select * from openjson(#json, '$[0].Names[0].NameLinkType.CommsChains.Value[0][0]');
select * from openjson(#json, '$[0].Names[0].NameLinkType.CommsChains.Value[0][0].com_recd'); --selecting path for com_recd
select * from openjson(#json, '$[0].Names[0].NameLinkType.CommsChains.Value[0][0].com_ack'); --selecting path for com_ack
Herein I show the selects to the different parts of your JSON. The arrays'content are always referenced as [0] as its always the first index to select here.
For more information on JSON paths on the SQL server look here

How to write an SQL query to genearte the empty json objects inside json object

I need an SQL query to get the below JSON object. I tried with FOR JSON PATH. Upto Model object I can get it. But inside JSON objects are not coming.
{
"Model": [
{
"ModelName": "Registration",
"Version": 1,
"Student": [
{
"StudentID": null,
"StudentName": null,
"Work": [
{
"WorkID": null,
"WorkNameName": null,
"Note": [
{
"NoteID": null,
"Comments": null,
"Visible": [
{
"IsVisible": null
}
]
}
]
}
]
}
]
}
]
}
Defining an nvarchar(max) variable (which is a valid JSON object) is always an option, but you may try to format the query results from a SELECT statement as JSON using FOR JSON AUTO. In this case the structure of the output JSON depends on the structure of the SELECT statement.
Statement:
DECLARE #ScriptData nvarchar(max)
SET #ScriptData =
(
SELECT
Model.ModelName, Model.Version,
Student.StudentID, Student.StudentName,
Work.WorkID, Work.WorkNameName,
Note.NoteID, Note.Comments,
Visible.IsVisible
FROM (VALUES ('Registration', 1)) Model (ModelName, Version)
CROSS APPLY (VALUES (NULL, NULL)) Student (StudentID, StudentName)
CROSS APPLY (VALUES (NULL, NULL)) Work (WorkID, WorkNameName)
CROSS APPLY (VALUES (NULL, NULL)) Note (NoteID, Comments)
CROSS APPLY (VALUES (NULL)) Visible (IsVisible)
FOR JSON AUTO, ROOT('Model'), INCLUDE_NULL_VALUES
)
Result:
{
"Model":[
{
"ModelName":"Registration",
"Version":1,
"Student":[
{
"StudentID":null,
"StudentName":null,
"Work":[
{
"WorkID":null,
"WorkNameName":null,
"Note":[
{
"NoteID":null,
"Comments":null,
"Visible":[
{
"IsVisible":null
}
]
}
]
}
]
}
]
}
]
}

Take json value in sql without JSON_VALUE

i want to take value (In SQL Server) in json object without JSON_VALUE
The json value :
{{
"Url": "****",
"Token": "",
"Data": {
"role_id": 1001,
"data": {
"stringvalue": [
{
"minage": "21"
},
{
"maxage": "55"
},
{
"primary_identity_file": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCcUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAIAcAmcAFHpFZEQyY1ZzbGVyRzNrcF8yTjhHHAIoAGJGQk1EMDEwMDBhYzAwMzAwMDAwMjMxMDAwMDQxNzQwMDAwYjQ3YjAwMDBhMTgyMDAwMDliY2EwMDAwMjkyMDAxMDBmODJhMDEwMGFiMzQwMTAwMDgzZTAxMDBjZGM0MDEwMP/iAhxJQ0NfUFJPRklMRQABAQAAAgxsY21zAhAAAG1udHJSR0IgWFlaIA"
}
]
}
}
}}
what i trying to do is to take "primary_identity_file" value
the result should be :
data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCcUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAIAcAmcAFHpFZEQyY1ZzbGVyRzNrcF8yTjhHHAIoAGJGQk1EMDEwMDBhYzAwMzAwMDAwMjMxMDAwMDQxNzQwMDAwYjQ3YjAwMDBhMTgyMDAwMDliY2EwMDAwMjkyMDAxMDBmODJhMDEwMGFiMzQwMTAwMDgzZTAxMDBjZGM0MDEwMP/iAhxJQ0NfUFJPRklMRQABAQAAAgxsY21zAhAAAG1udHJSR0IgWFlaIA
** NOTE primary_identity_file value is more than 10K character
I'd try something like that:
select substring(vlv3, 1, charindex('"', vlv3)-1) as vlv4
from (
select substring(vlv2, charindex('"', vlv2)+1, len(vlv2)) as vlv3
from (
select substring(vlv, charindex('"primary_identity_file"', vlv)+23, len(vlv)) as vlv2
from test
) as test2
) as test3
You can rewrite in more readable way as stored procedure
Sample fiddle http://sqlfiddle.com/#!18/a122b/7