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

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}]
}
}

Related

How do I parse nested JSON-objects in 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.

Postgres/JSON Updating nested array elements

Given the input JSON from the 'table' under a column named '_value'. I would like to replace the field "sc" as text from object to value of name under sc.
The json before updating looks like this.
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"sc": {
"web_link": "abc.com",
"name": "name"
}
}
},
{
"ao": {
"sc": ""
}
}
]
}
}
]
}
The json after updating should look like this.
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"sc": "name"
}
},
{
"ao": {
"sc": ""
}
}
]
}
}
]
}
I tried the below query to get to 'rules' array but having difficulty to proceed further in parsing and updating.
WITH values AS (
SELECT iprop -> 'value' -> 'rules' AS value FROM
table t,jsonb_array_elements(t._value->'iProps') AS
iprop )
SELECT *
from values, jsonb_array_elements(values.ao)
throws following error
ERROR: column values.ao does not exist
LINE 26: from values, jsonb_array_elements(values.ao)
^
SQL state: 42703
Character: 1396
You can try below mentioned query considering your structure is constant and the data type of your column is JSONB.
with cte as (
select
vals2->'ao'->'sc'->'name' as namevalue,
('{iProps,'||index1-1||',value,rules,'||index2-1||',ao,sc}')::text[] as json_path
from
table_,
jsonb_array_elements(value_->'iProps')
with ordinality arr1(vals1,index1),
jsonb_array_elements(vals1->'value'->'rules')
with ordinality arr2(vals2,index2)
)
update table_
set value_ = jsonb_set(value_,cte.json_path,cte.namevalue,false)
from cte
WHERE cte.namevalue IS NOT NULL
DEMO

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

How to create JSON Array Inside JSON object using FOR JSON SQL Server 2016

How to create JSON Array Inside JSON object using FOR JSON SQL Server 2016 (TABLE to JSON)
Here is my query:
SELECT
m.MeetingId AS tblMeeting_MeetingId,
m.Attended AS tblMeeting_Attended,
m3.CompanyId AS tblMeetingAttendants_CompanyId,
m3.MeetingAttendantsId AS tblMeetingAttendants_AttendantNameWithTitle,
m4.UserId AS tblMeetingAttendees_UserId,
m5.BrokerId AS tblMeetingBroker_BrokerId
FROM Bv.tblMeeting m
LEFT JOIN Bv.tblMeetingAttendants m3 ON m.MeetingId = m3.MeetingId
LEFT JOIN Bv.tblMeetingAttendees m4 ON m.MeetingId = m4.MeetingId
LEFT JOIN Bv.tblMeetingBroker m5 ON m.MeetingId = m5.MeetingId
WHERE m.MeetingId = 739
FOR JSON AUTO, INCLUDE_NULL_VALUES
Above query gives me result like this:
[
{
"tblMeeting_MeetingId": 739,
"tblMeeting_Attended": false,
"tblMeeting_MeetingSubject": " Benchmark China Internet Analyst",
"m3": [
{
"tblMeetingAttendants_CompanyId": 83,
"tblMeetingAttendants_AttendantNameWithTitle": 499,
"m4": [
{
"tblMeetingAttendees_UserId": null,
"m5": [
{
"tblMeetingBroker_BrokerId": 275
}
]
}
]
},
{
"tblMeetingAttendants_CompanyId": 83,
"tblMeetingAttendants_AttendantNameWithTitle": 500,
"m4": [
{
"tblMeetingAttendees_UserId": null,
"m5": [
{
"tblMeetingBroker_BrokerId": 275
}
]
}
]
},
{
"tblMeetingAttendants_CompanyId": 83,
"tblMeetingAttendants_AttendantNameWithTitle": 501,
"m4": [
{
"tblMeetingAttendees_UserId": null,
"m5": [
{
"tblMeetingBroker_BrokerId": 275
}
]
}
]
}
]
}
]
But i want result like this
[
{
"tblMeeting_MeetingId": 739,
"tblMeeting_Attended": false,
"tblMeeting_MeetingSubject": " Benchmark China Internet Analyst",
"tblMeetingAttendants_AttendantNameWithTitle": [499,500,501],
"tblMeetingAttendees_UserId": null,
"tblMeetingBroker_BrokerId": 275
}
]
Please reply as soon as possible
Thanks in advance.
It seems like this is impossible without using string concatenation and writing your own functions. There is no magic JSON_ARRAY_AGGREGATE() function. I have been looking for one myself.
Here is a related question: SQL Server 2016 for JSON output integer array
Can use JSON_QUERY with JSON PATH to format your data into a JSON array. I sampled just your MeetingID and MeetingAttendantID columns to demonstrate the concept
Build JSON Array using JSON_QUERY
DROP TABLE IF EXISTS #MeetingAttendance
CREATE TABLE #MeetingAttendance (MeetingID INT,AttendantID INT)
INSERT INTO #MeetingAttendance
VALUES (739,499)
,(739,500)
,(739,501)
SELECT tblMeeting_MeetingId = MeetingID
,tblMeetingAttendants_AttendantNameWithTitle = JSON_QUERY('['+STRING_AGG(CONCAT('"',AttendantID,'"'),',') + ']')
FROM #MeetingAttendance
GROUP BY MeetingID
FOR JSON PATH,WITHOUT_ARRAY_WRAPPER
Results
{
"tblMeeting_MeetingId": 739,
"tblMeetingAttendants_AttendantNameWithTitle": [
"499",
"500",
"501"
]
}