SQL - Json query - sql

I have tables similar to below where it has one to many mapping
DECLARE #T1 TABLE(RootId int, [Name] varchar(50))
DECLARE #T2 TABLE(Id int,RootId int, Category varchar(50))
INSERT INTO #T1
VALUES(1,'Some Name 12121'),(2,'Some Name 343434')
INSERT INTO #T2
VALUES(100,1,'Category 3333'),
(101,1,'Category 2222'),
(102,1,'Category 4444'),
(103,1,'Category 5555'),
(104,2,'Category 1111'),
(105,2,'Category 77777')
I am expecting to write query so it produce json as below format, where it had item and array of sub
[
{
"item": {
"rootId": 1,
"name": "Some Name 12121",
"sub": [
{
"id": 100,
"category": "Category 3333"
},
{
"id": 101,
"category": "Category 2222"
}
]
}
}
]
I have tried below but could not achieve the expected output
SELECT T1.RootId,T1.Name,T2.Id AS [Sub.Id],T2.Category as [Sub.Category]
FROM #T1 T1
INNER JOIN #T2 T2 ON T1.RootId = T2.RootId
FOR JSON PATH, root('item')
Is there a way to query so that it produce expected Json

All you need to do is (trivially) alias your table properly and then use AUTO instead of PATH:
SELECT T1.RootId,T1.Name,sub.Id AS Id,sub.Category as Category
FROM #T1 T1
INNER JOIN #T2 sub ON T1.RootId = sub.RootId
FOR JSON AUTO, ROOT('item');
Which outputs (after applying a format prettifier):
{
"item": [
{
"RootId": 1,
"Name": "Some Name 12121",
"sub": [
{
"Id": 100,
"Category": "Category 3333"
},
{
"Id": 101,
"Category": "Category 2222"
},
{
"Id": 102,
"Category": "Category 4444"
},
{
"Id": 103,
"Category": "Category 5555"
}
]
},
{
"RootId": 2,
"Name": "Some Name 343434",
"sub": [
{
"Id": 104,
"Category": "Category 1111"
},
{
"Id": 105,
"Category": "Category 77777"
}
]
}
]
}

Related

Get Hieararchical data as JSON from SQL Server

I have following table:
Id
HieararchyId
Name
1
/
MHz
2
/1/
Finance
3
/1/
IT
4
/1/3/
Software Development
5
/1/3/
QA
6
/1/2/
Accountant
and I want to get data for my TreeView like:
[
{
"Id": 1,
"HierarchyId": "/"
"Name":"MHz",
"Children":[
{
"Id": 3,
"HierarchyId": "/1/"
"Name":"IT",
"Children":[
{
"Id": 4,
"HierarchyId": "/1/3/"
"Name":"Software Development",
"Children":[]
}
{
"Id": 5,
"HierarchyId": "/1/3/"
"Name":"QA",
"Children":[]
}
]
},
{
"Id": 2,
"HierarchyId": "/1/"
"Name":"Finance",
"Children":[
{
"Id": 6,
"HierarchyId": "/1/2/"
"Name":"Accountant",
"Children":[]
}
]
}
]
}
]
I tried with this: How to generate hierarchical JSON data
Got error: No more lock classes available from transaction.
Or is it better creating recursive function and filling the Tree on client side?
Update
CREATE FUNCTION dbo.GetJson (#departmentId hierarchyid)
RETURNS nvarchar(max)
AS BEGIN
RETURN (
SELECT
Id,
HierarchyId,
Name,
children = JSON_QUERY(dbo.GetJson(HierarchyId))
FROM Departments p
WHERE p.HierarchyId.IsDescendantOf(#departmentId ) = 1
FOR JSON PATH
);
END;
The best way I have found to do this is to use a recursive function.
You can self-join all nodes and check if they are a child using GetAncestor
CREATE FUNCTION dbo.GetJson (#parentID hierarchyid)
RETURNS nvarchar(max)
AS BEGIN
RETURN (
SELECT
t.Id,
t.HierarchyId,
t.Name,
children = JSON_QUERY(dbo.GetJson(t.HierarchyId))
FROM Tree t
WHERE t.HierarchyId <> #parentID
AND t.HierarchyId.GetAncestor(1) = #parentID
FOR JSON PATH
);
END;
go
SELECT dbo.GetJson(hierarchyid::GetRoot());
db<>fiddle
Result
[
{
"Id": 1,
"HierarchyId": "/1/",
"Name": "MHz",
"children": [
{
"Id": 2,
"HierarchyId": "/1/2/",
"Name": "Finance",
"children": [
{
"Id": 6,
"HierarchyId": "/1/2/6/",
"Name": "Accountant"
}
]
},
{
"Id": 3,
"HierarchyId": "/1/3/",
"Name": "IT",
"children": [
{
"Id": 4,
"HierarchyId": "/1/3/4/",
"Name": "Software Development"
},
{
"Id": 5,
"HierarchyId": "/1/3/5/",
"Name": "QA"
}
]
}
]
}
]

Select data from Json array MS SQL Server

I have to select data from Json like this:
[
{
"id": 10100,
"externalId": "100000035",
"name": "Test1",
"companyId": 10099,
"phone": "0738003811",
"email": "test#Test.com",
"mainAddress": {
"county": "UK",
"province": "test",
"zipCode": "01234",
"city": "test",
"street": "test",
"gln": "44,37489331;26,21941193",
"country": {
"iso2": "UK",
"iso3": "UK"
}
},
"active": false,
"main": true,
"stores": [
"Test"
],
"attributes": [
{
"attributeId": 1059,
"attributeName": "CH6 name",
"attributeExternalId": null,
"attributeValueId": 74292,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": null,
"attributePlainValue": "Unknown"
},
{
"attributeId": 1061,
"attributeName": "BD",
"attributeExternalId": null,
"attributeValueId": 81720,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": null,
"attributePlainValue": "Not assigned"
}
],
"daysSinceLastOrder": null
},
{
"id": 62606,
"externalId": "VL_LC_000190",
"name": "Test",
"companyId": 17793,
"phone": "44333424",
"email": "test#email.com",
"mainAddress": {
"firmName": "test",
"county": "test",
"province": "test",
"zipCode": "247555",
"city": "test",
"street": "test",
"gln": "44.8773851;23.9223518",
"country": {
"iso2": "RO",
"iso3": "ROU"
},
"phone": "07547063789"
},
"active": true,
"main": false,
"stores": [
"Valcea"
],
"attributes": [
{
"attributeId": 1042,
"attributeName": "Type of location",
"attributeExternalId": "TYPE_OF_DIVISION",
"attributeValueId": 34506,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": "Small OTC (<40mp)",
"attributePlainValue": "Small OTC (<40mp)"
},
{
"attributeId": 17,
"attributeName": "Limit for payment",
"attributeExternalId": "LIMIT_FOR_PAYMENT_IN_DAYS",
"attributeValueId": 59120,
"attributeValueType": "NUMBER",
"attributeValueEid": null,
"attributePlainValue": "28"
}
],
"daysSinceLastOrder": 147
}
]
I know how to select data from simple json object using "FROM OPENJSON",
but now I have to select a
AttributeValueId, AttributeId and AttributeName, attributePlainValue and CompanyId for each Attribute. So I dont know how to select data from attributes array and then how to join to this CompanyId which is one level up.
Maybe someone knows how write this query.
As mentioned by #lptr in the comments:
You need to pass the result of one OPENJSON to another, using CROSS APPLY. You can select a whole JSON object or array as a property, by using the syntax AS JSON
select
t1.companyid,
t2.*
from openjson(#j)
with (
companyId int,
attributes nvarchar(max) as json
) as t1
cross apply openjson(t1.attributes)
with
(
attributeId int,
attributeName nvarchar(100),
attributeValueId nvarchar(100),
attributePlainValue nvarchar(100)
) as t2;
db<>fiddle
For example, you can use code like this.
f1.metaData->"$.identity.customerID" = '.$customerID.'

Postgresql and jsonb - inserting a key/value into a multi-level array

Very similar to this post, but I struggle to adapt from their solution..
My table : public.challenge, column lines JSONB
My initial JSON in lines :
[
{
"line": 1,
"blocs": [
{
"size": 100,
"name": "abc"
},
{
"size": 100,
"name": "def"
},
{
"size": 100,
"name": "ghi"
}
]
},
{
"line": 2,
"blocs": [
{
"size": 100,
"name": "xyz"
}
]
}
]
Desired update :
[
{
"line": 1,
"blocs": [
{
"size": 100,
"name": "abc",
"type": "regular"
},
{
"size": 100,
"name": "def",
"type": "regular"
},
{
"size": 100,
"name": "ghi",
"type": "regular"
}
]
},
{
"line": 2,
"blocs": [
{
"size": 100,
"name": "xyz",
"type": "regular"
}
]
}
]
So basically I need to add the type key+value in every object of blocs, for each element of the root array.
My unsuccessful attempt looks like this :
UPDATE public.challenge SET lines = jsonb_set(lines, '{}', (
SELECT jsonb_set(line, '{blocs}', (
SELECT jsonb_agg( bloc || '{"type":"regular"}' )
FROM jsonb_array_elements(line->'{blocs}') bloc
))
FROM jsonb_array_elements(lines) line
))
;
(currently it sets the whole column as null, maybe due to jsonb_set(lines, '{}' while my json begins as an array ?)
Thanks!
Use jsonb_array_elements to unnest all the array elements and then add the required json and use jsonb_agg to aggregate it again:
with cte as
(select id,
jsonb_agg(jsonb_set(val1,
'{blocs}',
(select jsonb_agg(arr2 || '{"type": "regular"}')
from jsonb_array_elements(arr1.val1 - >
'blocs') arr2)))
from challenge,
jsonb_array_elements(lines) arr1(val1)
group by 1)
update challenge
set lines = (cte.jsonb_agg)
from cte
where challenge.id = cte.id
DEMO

Convert table to JSON array with longtext column

I'm using mariaDB 10.3, I have a table:
CREATE TABLE user(id INT NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, parameters longtext, PRIMARY KEY(id));
With rows:
INSERT INTO user VALUES (1, 'name1', '{"number": 1, "text": "some text"}'), (2, 'name2', '{"number": 2, "text": "some more text"}');
I'm trying to write query that returns the table as JSON object.
So far I have
SELECT CONCAT(
'[',
GROUP_CONCAT(JSON_OBJECT('id',id,'name',name,'parameters', parameters)),
']'
)
FROM user;
But this returns:
[
{"id": 1,
"name": "name1",
"parameters": "{\"number\": 1, \"text\": \"some text\"}"
},
{
"id": 2,
"name": "name2",
"parameters": "{\"number\": 2, \"text\": \"some more text\"}"
}
]
which is not a proper JSON. What should I change to get parameters properly formatted?
What I would like to get is:
[
{
"id": 1,
"name": "name1",
"parameters": {
"number": 1,
"text": "some text"
}
},
{
"id": 2,
"name": "name2",
"parameters": {
"number": 2,
"text": "some more text"
}
}
]
Thanks
Just JSON_COMPACT function, which's proper to MariaDB and does not exists in MySQL, might be applied for the parameters column
SELECT CONCAT(
'[',
GROUP_CONCAT(JSON_OBJECT('id',id,
'name',name,'parameters',
JSON_COMPACT(parameters))),
']'
) AS "JSON Value"
FROM user
Demo

SQL Query to get the count of Json Array

I have the below Json object. How do I get the count of Object Array.
{
"Model": [
{
"ModelName": "Test Model",
"Object": [
{
"ID": 1,
"Name": "ABC"
},
{
"ID": 11,
"Name": "ABCD"
},
]
}]}
I tried the below query but seems JSON_Length was not available.
SELECT ModelName,
JSON_LENGTH(JsonData, '$.Model[0].Object')
FROM TabA
The expected output should be
ModelName COUNT
Test Model 2
If you have valid JSON (at the moment you have a trailing comma (,_ after one of your closing braces (})), then you could use OPENJSON and COUNT:
DECLARE #JSON nvarchar(MAX) = N'{
"Model": [
{
"ModelName": "Test Model",
"Object": [
{
"ID": 1,
"Name": "ABC"
},
{
"ID": 11,
"Name": "ABCD"
}
]
}]}';
SELECT M.ModelName,
COUNT(O.[key]) AS [Count]
FROM (VALUES(#JSON))V(J)
CROSS APPLY OPENJSON(V.J)
WITH(ModelName varchar(20) '$.Model[0].ModelName',
[Object] nvarchar(MAX) '$.Model[0].Object' AS JSON) M
CROSS APPLY OPENJSON(M.[Object]) O
GROUP BY M.ModelName;