TSQL FOR JSON nested value - json

I am trying to output JSON via tsql hierarchy table.
Code:
select Field1, Field2 from #header inner join #line on #header.Id = #Line.Id FOR JSON AUTO
I am getting:
"Field1": "BOB",
"Field2": "BOB2",
but I am looking for it to display
"Field1": {
"value": "BOB"
},
"Field2": {
"value": "BOB2"
},
What am I doing wrong? I can using text manipulation, but was wondering if there is a "blessed" way, i.e. built-in that is readable and best-practice.

Select STRING_AGG(concat('"',[Key],'":{"value":"',string_escape(Value,'json'),'"}'),',')
From OpenJson( (Select * From #YourTable For JSON Path,Without_Array_Wrapper ) )
For 2016 -- STUFF XML
Select stuff((Select concat('"',[Key],'":{"value":"',string_escape(Value,'json'),'"}')
From OpenJson( (Select * From #YourTable For JSON Path,Without_Array_Wrapper ) )
For XML Path ('')),1,0,'')
Results
"Field1":{
"value":"Bob"
},
"Field2":{
"value":"Bob2"
}

You can just use a path for each column name, combined with FOR JSON PATH.
SELECT
Field1 AS [Field1.value],
Field2 AS [Field2.value]
FROM #header h
JOIN #line l ON h.Id = l.Id
FOR JSON PATH;
If you need the two fields as entirely separate rows each with its own object, you can unpivot it
SELECT
v.[Field1.value],
v.[Field2.value]
FROM #header h
JOIN #line l ON h.Id = l.Id
CROSS APPLY (VALUES
(Field1, NULL),
(NULL, Field2)
) v([Field1.value], [Field2.value])
FOR JSON PATH;

Related

MariaDB: sum values from JSON

I'd like to sum up certain values from a JSON snippet following this example data:
set #json='
{
"items": [
{
"a": {
"a_amount": "0.0020095"
},
"b": {
"b_amount": "0.0004"
}
},
{
"a": {
"a_amount": "0.02763081"
},
"b": {
"b_amount": "0.0055"
}
}
]
}';
I need to sum all a.a_amount and all b.b_amount independantly, so I'd like to do something like SUM(a.a_amount) and SUM(b.b_amount).
But I haven't gotten any further than extracting the respective values like this:
SELECT JSON_EXTRACT(#json, '$.items[*].a.a_amount') AS sum_a,
JSON_EXTRACT(#json, '$.items[*].b.b_amount') AS sum_b;
sum_a
sum_b
["0.0020095", "0.02763081"]
["0.0004", "0.0055"]
I've fiddled around with JSON_EXTRACT(), JSON_VALUE() and even the ha_connect plugin but still couldn't come up with SQL code that would give me the sums I need.
Who can help me here?
One option is using a DOUBLE conversion along with Recursive CTE through use of JSON_EXTRACT() function such as
WITH RECURSIVE cte AS
(
SELECT 0 i
UNION ALL
SELECT i + 1 i
FROM cte
WHERE i + 1 <= ( SELECT JSON_LENGTH(json) FROM j )
)
SELECT SUM(CAST(JSON_EXTRACT(json, CONCAT('$.items[',i,'].a.a_amount')) AS DOUBLE)) AS sum_a,
SUM(CAST(JSON_EXTRACT(json, CONCAT('$.items[',i,'].b.b_amount')) AS DOUBLE)) AS sum_b
FROM cte,
j
sum_a
sum_b
0.02964031
0.0059
Demo
The JSON Table function could help you. Here a small example with your data. Maybe you must play a little bit with the data types.
SELECT
SUM(a_amount),
SUM(b_amount)
FROM
(
SELECT * FROM
JSON_TABLE(#json, '$.items[*]' COLUMNS(
a_amount FLOAT PATH '$.a.a_amount',
b_amount FLOAT PATH '$.b.b_amount'
)
) as items
) as temp;
SUM(a_amount)
SUM(b_amount)
0.029640309745445848
0.005899999960092828
View on DB Fiddle

Json conversion in SQL Server - multiple rows in to single json array

Dataset :
create table grievances(grivanceid int ,grivancedesc varchar(10))
create table grievanceType(grivanceid int ,grivanceType varchar(10))
insert into grievances values (1,'abc')
insert into grievanceType values (1,'type1')
insert into grievanceType values (1,'type2')
Desired output:
{
"grivanceid": 1,
"grivancedesc": "abc",
"grivanceType": [ "type1", "type2"]
}
My query : not fully achieved
select *
from
(select
a.*,
stuff(list.grivanceType, 1, 1, '') grivanceType
from
grievances a
cross apply
(select
',' + grivanceType
from
grievanceType b
where
grivanceid = a.grivanceid
for xml path ('')
) list(grivanceType)) a
for json path, without_array_wrapper
It helps if you wrap your XML results in a JSON_Query()
Example
Select *
,grivanceType = JSON_QUERY('['+stuff((Select concat(',"',grivanceType,'"' )
From grievanceType
Where grivanceid =A.grivanceid
For XML Path ('')),1,1,'')+']'
)
From grievances A
for json path, without_array_wrapper
Returns
{
"grivanceid": 1,
"grivancedesc": "abc",
"grivanceType": ["type1", "type2"]
}

postgres jsonb update array element based on different array element

I want to update ContextItems where id=993, changing label from 'Jane's Trucking' to 'newname'.
I do not want other data to change.
Initial data:
{
"UserId": "JohnDoe",
"ContextItems": "{\"Entity\":{\"items\":[{\"id\":993,\"label\":\"Jane's Trucking\",\"viewModelId\":\"EntityEdit\"},{\"id\":992,\"label\":\"Bob's Flowers\",\"viewModelId\":\"EntityEdit\"}],\"targetView\":\"EntityViewEdit\"}}"
}
I have managed to manipulate data, however, the layout has changed from above to json:
[{
"viewmodelid": "EntityEdit",
"id": "993",
"label": "newname"
},{
"viewmodelid": "EntityEdit",
"id": "992",
"label": "Bob's Flowers"
}]
This is the code that achieved this. What else is needed to convert back from json to what I guess was some sort of text in ContextItems?
with temp1 as
(select (jsondoc_->'ContextItems' #>> '{}')::jsonb ->'Entity'-->'items'
as jsonfield , id_ , jsondoc_ from usersetting where id_='21|77')
, temp2 as
(select obj->>'label' as label, obj->>'id' as id, obj->>'viewModelId' as viewModelId, id_
from temp1, jsonb_array_elements(temp1.jsonfield->'items') obj(val) )
, temp3 as
(select id, case when id='993' then 'newname' else label end as label ,viewModelId
from temp2)
select json_agg(temp3) as origjson FROM temp3 where id in ('993','992')

How to explode several list values JSON within JSON with lateral flatten in Snowflake?

I have a variant table with 24 JSONs like the following (one per row):
{
"context": "marketplace",
"metadata": {
"app_version": "1.0.4 (166)",
},
"params": {
"filter": {
"brands": [],
"categories": [
"f28c7c9f-09ae-4218-821a-bec344998289"
],
"manufacturers": [],
"page": 1,
"product_name": "",
},
"page": "product_list",
"results": 3
},
"user_id": "6443a2db-4526-4fc5-8084-290fc78e5336"
}
I want everything exploded in rows. I have managed to have everything but filter as I want with the code:
SELECT data:event::string,
data:user_id::string,
data:metadata.app_version::string,
data:context::string,
data:params.page::string,
data:params.filter.page::string,
data:params.results::string
FROM ods.stg_tanimis_events
The lists brands, categories and manufacturers can be empty but I would need a null value if that is the case. I would like to have a table with the following columns:
event, user_id, app_version, context, param_page, filter_page, results, manufacturer, brand, category
I have tried with several lateral flatten with no success:
select * FROM table
, lateral flatten (data:params:filter:categories) j2;
select * FROM table
, lateral flatten (data:params:filter.brands) j1
select * FROM table
, lateral flatten (data:params:filter:brands) j1
, lateral flatten (data:params:filter:categories) j2;
select user_id, filter, flat.*
from table
, lateral flatten(parse_json(filter)) flat;
WITH j as (
SELECT *
FROM table
, lateral flatten(data:params:filter))
SELECT *
from j,
lateral flatten (j.value) j2;
Either way, I get 8 rows or 0 rows, or errors. How could I make it? Thanks
In your example data, there is no data in "brands", which means any flatten against that will return nothing unless you add , OUTER => TRUE in your lateral flatten statement. Something more like this:
SELECT table.data:event::string,
table.data:user_id::string,
table.data:metadata.app_version::string,
table.data:context::string,
table.data:params.page::string,
table.data:params.filter.page::string,
table.data:params.results::string,
j1.value::string as brands,
j2.value::string as categories
FROM table
, lateral flatten (data:params:filter:brands, OUTER => TRUE) j1
, lateral flatten (data:params:filter:categories, OUTER => TRUE) j2;
This will act like a LEFT JOIN to the base table and return NULL for any flattened arrays that are empty.

Using sub queries to create JSON file

I'm trying to create a JSON file for a new project that I'm currently looking into I've got most of it working as expected but I'm now at a point where I'm trying to use sub queries in order to format the JSON correctly.
I've tried to use the following sub query but SQL doesn't like the formatting.
` SELECT
'Admin User TEST ONLY PLEASE IGNORE' AS AdditionalNotes
(
SELECT v.atFault
FROM dbo.ic_DP_AX ax
CROSS APPLY (VALUES (ax.Acc_fault1), (ax.Acc_fault2)) v (atFault)
FOR JSON AUTO
) AS InsuredPartyClaims,
(
SELECT Acc_fault3 AS atFault
FROM dbo.ic_DP_AX
FOR JSON AUTO
) AS InsuredPartyConvictions
FOR JSON PATH) ROOT('InsuredParties')
FROM
dbo.icp_Daprospect AS p INNER JOIN
dbo.icp_Dapolicy AS d ON p.Branch# = d.Branch# AND p.ClientRef# =
d.ClientRef# LEFT OUTER JOIN
dbo.ic_DP_AX AS ax ON P.Branch# = ax.B# AND ax.PolRef# = d.PolicyRef#
LEFT OUTER JOIN
WHERE
d.PolicyRef# = '' AND
d.Branch# = 0`
FOR JSON PATH
The output I'm trying to achieve is:
"InsuredParties": [
{
"InsuredPartyClaims": [
{
"atFault": false
},
{
"atFault": true
}
],
"InsuredPartyConvictions": [
{
"atFault": false
},
Can anyone see what I'm doing wrong? I'm trying to keep this as simple as possible.
It's always difficult without sample data, but the foolowing example is a possible solution:
Table:
CREATE TABLE dbo.ic_DP_AX (Acc_fault1 bit, Acc_fault2 bit, Acc_fault3 bit)
INSERT INTO dbo.ic_DP_AX (Acc_fault1, Acc_fault2, Acc_fault3)
VALUES (0, 1, 0)
Statment:
SELECT
(
SELECT v.atFault
FROM dbo.ic_DP_AX ax
CROSS APPLY (VALUES (ax.Acc_fault1), (ax.Acc_fault2)) v (atFault)
FOR JSON AUTO
) AS InsuredPartyClaims,
(
SELECT Acc_fault3 AS atFault
FROM dbo.ic_DP_AX
FOR JSON AUTO
) AS InsuredPartyConvictions
FOR JSON PATH, ROOT('InsuredParties')
Result:
{
"InsuredParties":[
{
"InsuredPartyClaims":[
{
"atFault":false
},
{
"atFault":true
}
],
"InsuredPartyConvictions":[
{
"atFault":false
}
]
}
]
}
The subqueries need to return JSON as well.
Try
(
(SELECT ax.Acc_fault1 AS [atFault] FROM dbo.ic_DP_AX AS ax FOR JSON PATH) AS [PartyClaims]
(SELECT ax.Acc_fault2 AS [atFault] FROM dbo.ic_DP_AX AS ax FOR JSON PATH) AS [PartyClaims]
(SELECT ax.Acc_fault3 AS [atFault] FROM dbo.ic_DP_AX AS ax FOR JSON PATH) AS [PartyConvictions]
) FOR JSON PATH AS [InsuredParties]