Parse JSON text inside NVARCHAR column when using FOR JSON PATH - sql

Suppose that I have a table with a records like this:
CREATE TABLE json_store (
[id] INT IDENTITY(1, 1) PRIMARY KEY,
[json_data] NVARCHAR(MAX)
)
id | json_data
------------------------------------------
1 | {"data_in_json": "Hello from 1"}
2 | {"data_in_json": "Hello from 2"}
3 | {"data_in_json": "Hello from 3", "remarks": "I have a different structure"}
and I want a JSON result like this:
[
{
"id": 1,
"json_data": {"data_in_json": "Hello from 1"}
},
{
"id": 2,
"json_data": {"data_in_json": "Hello from 2"}
},
{
"id": 3,
"json_data": {"data_in_json": "Hello from 3", "remarks": "I have a different structure"}
}
]
I've been using FOR JSON PATH but the problem is it returns JSON as an escaped string.
SELECT [id], [json_data]
FROM [json_store]
FOR JSON PATH
[
{
"id": 1,
"json_data": "{\"data_in_json\": \"Hello from 1\"}"
},
{
"id": 2,
"json_data": "{\"data_in_json\": \"Hello from 2\"}"
},
{
"id": 3,
"json_data": "{\"data_in_json\": \"Hello from 3\", \"remarks\": \"I have a different structure\"}"
}
]
I wanted to know is it possible to parse a JSON column along with the result?
Also, I've tried using OPENJSON() to parse and use FOR JSON PATH convert it back to JSON but it does break the structure into [{"key": ..., "value": ...}, ...]

You need to convert your NVARCHAR(MAX) column json_data to JSON first, using JSON_QUERY, so that SQL Server knows it is already JSON and won't escape it:
CREATE TABLE #T (id INT, json_data NVARCHAR(MAX));
INSERT #T(id, json_data)
VALUES
(1, '{"data_in_json": "Hello from 1"}'),
(2, '{"data_in_json": "Hello from 2"}'),
(3, '{"data_in_json": "Hello from 3", "remarks": "I have a different structure"}');
SELECT id, JSON_QUERY(t.json_data) AS json_data
FROM #T AS t
FOR JSON AUTO;
Which gives:
[
{
"id": 1,
"json_data": {
"data_in_json": "Hello from 1"
}
},
{
"id": 2,
"json_data": {
"data_in_json": "Hello from 2"
}
},
{
"id": 3,
"json_data": {
"data_in_json": "Hello from 3",
"remarks": "I have a different structure"
}
}
]

Related

get Json values and Json string from Json Array in SQL Server

I have a JSON string like this:
{
"success": "true",
"data": [
{ "ID": 1, "name": "abc" },
{ "ID": 2, "name": "def" }
]
}
I need output like below:
ID
name
JsonString
1
abc
{"ID": 1, "name": "abc"}
2
def
{"ID": 2, "name": "def"}
I need the query in SQL Server
The only interesting things here are the initial path to OPENJSON (since we only care about data) and the property JsonString reflecting the original JSON, which needs a path and an override.
DECLARE #json NVARCHAR(MAX) = '{"success":"true","data":[{"ID":1,"name":"abc"},{"ID":2,"name":"def"}]}';
SELECT *
FROM OPENJSON(#json, '$.data')
WITH (ID INT, name VARCHAR(100), JsonString NVARCHAR(MAX) '$' AS JSON)

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 - Json query

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

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;

SQL JSON : Nest few nodes under a custom node using sql query FOR JSON

So I have written a query that gives the output as an array of JSON objects, one of the objects is below
{
"cardType": "abc",
"createdOnDateTime": "2020-03-26",
"courseName": "course1",
"courseID": 1,
"sectionName": 1,
"studentList": [
{
"name": "student 1",
"nameLink": "0"
},
{
"name": "student 2",
"nameLink": "0"
},
{
"name": "student 3",
"nameLink": "0"
}
]
}
But I want the output as
{
"cardType": "abc",
"createdOnDateTime": "2020-03-26",
"payload" : {
"courseName": "course1",
"courseID": 1,
"sectionName": 1,
"studentList": [
{
"name": "student 1",
"nameLink": "0"
},
{
"name": "student 2",
"nameLink": "0"
},
{
"name": "student 3",
"nameLink": "0"
}
]
}
}
I have used 'For JSON Auto' phrase at the end of my Select query and as the course and student has a One-to-many relation, the student gets formatted in an array. What I want is that few nodes along with the "studentList" node array should be nested under a custom node 'payload'. How can this be achieved in SQL query using the For JSON and it's related properties?
Totally guessing here on what your data and query looks like based on what little you've given us so far. Use a subquery for studentList with for json auto then, on your outer query use for json path, without_array_wrapper.
When using for json path you can nest elements inside each other by giving them dot-separated paths, i.e.: separating parent elements from children with period (.) characters, such as the following...
create table dbo.Course (
cardType nvarchar(3),
createdOnDateTime date,
courseName nvarchar(20),
courseID int,
sectionName int
);
insert dbo.Course values
('abc', '2020-03-26', 'course1', 1, 1);
go
create table dbo.Student (
courseID int,
name nvarchar(20),
nameLink nvarchar(20)
);
insert dbo.Student values
(1, 'student 1', '0'),
(1, 'student 2', '0'),
(1, 'student 3', '0');
go
select
cardType,
createdOnDateTime,
[payload.courseName] = courseName,
[payload.courseID] = courseID,
[payload.sectionName] = sectionName,
[payload.studentList] = (
select name, nameLink
from dbo.Student S1
where S1.courseID = C1.courseID
for json auto
)
from dbo.Course C1
where courseID = 1
for json path, without_array_wrapper;
go
Which yields the result...
{
"cardType": "abc",
"createdOnDateTime": "2020-03-26",
"payload": {
"courseName": "course1",
"courseID": 1,
"sectionName": 1,
"studentList": [
{
"name": "student 1",
"nameLink": "0"
},
{
"name": "student 2",
"nameLink": "0"
},
{
"name": "student 3",
"nameLink": "0"
}
]
}
}
My query was resolved eventually, I found this really helpful video on youtube that exactly shows what I had to do. Click here for the video.
Also one more thing, this video is a very good example, but for large size data, this approach makes the query very slow.