Convert table to JSON array with longtext column - sql

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

Related

Extract text from JSON in SQL Server

I am trying to extract a specific value from a JSON column in SQL Server. Unfortunately I have read several posts on this topic but still cannot figure out how to translate their solutions to what I need. I am looking to extract "foo testing" but simply do not understand how to get at this with a nested JSON. Can someone please advise?
The structure of the JSON column is:
{
"values": [
{
"id": "x01",
"status": "STATUS1",
"subStatus": "SubStatus1",
"values": [
{
"key": "dropdown",
"value": "",
"optionType": null
}
]
},
...
{
"id": "x03",
"status": "STATUS3",
"subStatus": "SubStatus3",
"values": [
{
"key": "dropdown",
"value": "",
"optionType": null
},
{
"key": "textInput",
"value": null,
"optionType": null
},
{
"key": "checkbox1",
"value": true,
"optionType": null
},
{
"key": "textInput2",
"value": "foo testing",
"optionType": null
}
]
}
]
}
The statement depends on the structure of the parsed JSON, in your case you need to use two nested OPENJSON() calls and additinal APPLY operators. Note, that you need to use AS JSON in a "values" column definition to specify that the referenced property contains an inner JSON array and the type of that column must be nvarchar(max).
Test table:
DECLARE #json varchar(max) = '
{
"values": [
{
"id": "x01",
"status": "STATUS1",
"subStatus": "SubStatus1",
"values": [
{"key": "dropdown", "value": "", "optionType": null}
]
},
{
"id": "x03",
"status": "STATUS3",
"subStatus": "SubStatus3",
"values": [
{"key": "dropdown", "value": "", "optionType": null},
{"key": "textInput", "value": null, "optionType": null},
{"key": "checkbox1", "value": true, "optionType": null},
{"key": "textInput2", "value": "foo testing", "optionType": null}
]
}
]
}
'
SELECT JsonColumn
INTO JsonTable
FROM (VALUES (#json)) v (JsonColumn)
Statement:
SELECT j1.[id], j2.[key], j2.[value] -- or add all columns
FROM JsonTable t
CROSS APPLY OPENJSON(t.JsonColumn, '$.values') WITH (
[id] varchar(3) '$.id',
[status] varchar(30) '$.status',
[subStatus] varchar(30) '$.subStatus',
[values] nvarchar(max) '$.values' AS JSON
) j1
CROSS APPLY OPENJSON(j1.[values], '$') WITH (
[key] varchar(50) '$.key',
[value] varchar(50) '$.value',
[optionType] varchar(50) '$.optionType'
) j2
Result:
id key value
---------------------------
x01 dropdown
x03 dropdown
x03 textInput
x03 checkbox1 true
x03 textInput2 foo testing
you can use following query
;with summery as(
SELECT *
FROM OPENJSON((SELECT value FROM OPENJSON(#json)))
WITH (
id NVARCHAR(50) 'strict $.id',
status NVARCHAR(50) '$.status',
subStatus NVARCHAR(50) '$.subStatus',
[values] NVARCHAR(max) '$.values' AS JSON
)
)
select id,status,subStatus,[key],value,optionType from summery
CROSS APPLY OPENJSON(summery.[values])
WITH (
[key] NVARCHAR(50) '$.key',
[value] NVARCHAR(50) '$.value',
[optionType] NVARCHAR(50) '$.optionType'
);
demo in db<>fiddle

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

Parse JSON text inside NVARCHAR column when using FOR JSON PATH

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

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;

JSON from SQL query with child level

I have a simple query in my database:
SELECT id, name FROM users FOR JSON AUTO, ROOT('users')
This returns the following JSON:
{
"users": [
{"id": "1", "name": "John"}
{"id": "2", "name": "Mike"}
]
}
I want to have the return with the following format:
{
"users": {
"list": [
{"id": "1", "name": "John"}
{"id": "2", "name": "Mike"}
]
}
}
Can I do this on SQL level by simply changing the query?
You may try with this:
Table:
CREATE TABLE users (
id varchar(1),
[name] varchar(50)
)
INSERT INTO users
(id, [name])
VALUES
('1', 'John'),
('2', 'Mike')
Statement:
SELECT users = (SELECT id, name FROM users FOR JSON AUTO, ROOT('list'))
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
Result:
{"users":{"list":[{"id":"1","name":"John"},{"id":"2","name":"Mike"}]}}