SQL to JSON - Grouping Results into JSON Array combine columns - sql

In SQL Server I have a table with columns (a, b, c, name1, address1, phonenumber1, name2, address2, phonenumber2). I want to generate JSON for a row like:
{
"a" : value_column_a,
"b" : value_column_b,
"c" : value_column_c,
"contacts": [
{
"name" : name1,
"phone_num": phonenumber1,
"address": address1
},
{
"name" : name2,
"phone_num": phonenumber2,
"address": address2
}
]
}
Please, help me! I took some hours, but I could not solved it.

Embedding arrays of objects into JSON on Microsoft SQL Server is achieved by using json_query() over a subquery of the nested data, such as the following...
/*
* Data setup...
*/
create table dbo.Thingiebob (
[a] varchar(14),
[b] varchar(14),
[c] varchar(14),
[name1] varchar(14),
[address1] varchar(14),
[phonenumber1] varchar(14),
[name2] varchar(14),
[address2] varchar(14),
[phonenumber2] varchar(14)
);
insert dbo.Thingiebob ([a], [b], [c], [name1], [address1], [phonenumber1], [name2], [address2], [phonenumber2])
values
('value_column_a', 'value_column_b', 'value_column_c', 'name1', 'address1', 'phonenumber1', 'name2', 'address2', 'phonenumber2');
/*
* Example query...
*/
select
[a],
[b],
[c],
json_query((
select *
from (
select name1, phonenumber1, address1
union
select name2, phonenumber2, address2
) unions ([name], [phone_num], [address])
for json path
), '$') as [contacts]
from dbo.Thingiebob
for json path;
Which yields the following output...
[
{
"a": "value_column_a",
"b": "value_column_b",
"c": "value_column_c",
"contacts": [
{
"name": "name1",
"phone_num": "phonenumber1",
"address": "address1"
},
{
"name": "name2",
"phone_num": "phonenumber2",
"address": "address2"
}
]
}
]

Related

OPENJSON does not detect duplicated Value

I need to import and parse some sales records into the database.
Some customers have more than one product, therefore there are several orders with different product but with the same shipping address in the JSON Array.
Problem arise when I try to save the address in Addresses Table:
Clearly I need just one record for each Address, and to achieve this I calculate an Hash of the address fields and I compare it with the Hashes already present in the table:
It seems (well, I'm sure) that the query checks only the first time if the Hash is already present, and if it is not present, it add as many rows as the orders count:
I can imagine this is the standard behavior of OPENJSON function since the parsing of the JSON payload seems to be made by an inner loop, therefore I think I have to use a different approach.... but I have no Idea what to use.
here the JSON payload
declare #json nvarchar(max)=N'[
{
"id": 21660,
"currency": "USD",
"total": "15.00",
"shipping": {
"first_name": "Charles",
"last_name": "Leuschke",
"address_1": "3121 W Olive Ave",
"city": "Burbank",
"state": "CA",
"postcode": "91505",
"country": "US"
},
"line_items": [
{
"id": 1052
}
]
},
{
"id": 21659,
"currency": "USD",
"total": "38.00",
"shipping": {
"first_name": "Charles",
"last_name": "Leuschke",
"address_1": "3121 W Olive Ave",
"city": "Burbank",
"state": "CA",
"postcode": "91505",
"country": "US"
},
"line_items": [
{
"id": 1050
}
]
},
{
"id": 21658,
"currency": "USD",
"total": "38.00",
"shipping": {
"first_name": "Charles",
"last_name": "Leuschke",
"address_1": "3121 W Olive Ave",
"city": "Burbank",
"state": "CA",
"postcode": "91505",
"country": "US"
},
"line_items": [
{
"id": 1048
}
]
}
]'
and the (simplified) query
Insert Into #Addresses
(
orderId,
fullName,
addressLine1,
city,
stateOrProvince,
postalCode,
countryCode,
addressCode
)
SELECT
o.orderId,
concat(s.firstName,' ',s.lastName),
s.addressLine1,
s.city,
s.stateOrProvince,
s.postalCode,
s.countryCode,
convert(nvarchar(64),hashbytes('SHA1',concat(s.firstName, ' ', s.lastName, s.addressLine1, s.city, s.stateOrProvince, s.postalCode, s.countryCode)),2)
FROM OPENJSON(#json)
WITH (
orderId nvarchar(64) '$.id',
shipping nvarchar(max) '$.shipping' AS JSON
) o
CROSS APPLY OPENJSON(shipping)
WITH (
firstName nvarchar(128) '$.first_name',
lastName nvarchar(128) '$.last_name',
addressLine1 nvarchar(128) '$.address_1',
city nvarchar(128) '$.city',
stateOrProvince nvarchar(64) '$.state',
postalCode nvarchar(64) '$.postcode',
countryCode nvarchar(4) '$.country'
) s
left join #Addresses a on a.addressCode=convert(nvarchar(64),hashbytes('SHA1',concat(s.firstName,' ', s.lastName, s.addressLine1, s.city, s.stateOrProvince, s.postalCode, s.countryCode)),2)
where a.addressCode is null
I also prepared a sqlfiddle, where you can see that it returns 3 rows while target is to get just one
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=3031a99e3cd24f6bf383c0de29cf19a1
Just use the standard ROW_NUMBER() deduplication method e.g.
WITH cte AS (
SELECT
o.orderId,
concat(s.firstName,' ',s.lastName) fullName,
s.addressLine1,
s.city,
s.stateOrProvince,
s.postalCode,
s.countryCode,
h.addressCode,
ROW_NUMBER() OVER (PARTITION BY h.addressCode ORDER BY o.OrderId ASC) rn
FROM OPENJSON(#json)
WITH (
orderId nvarchar(64) '$.id',
shipping nvarchar(max) '$.shipping' AS JSON
) o
CROSS APPLY OPENJSON(shipping)
WITH (
firstName nvarchar(128) '$.first_name',
lastName nvarchar(128) '$.last_name',
addressLine1 nvarchar(128) '$.address_1',
city nvarchar(128) '$.city',
stateOrProvince nvarchar(64) '$.state',
postalCode nvarchar(64) '$.postcode',
countryCode nvarchar(4) '$.country'
) s
CROSS APPLY (
VALUES (CONVERT(nvarchar(64), HASHBYTES('SHA1', CONCAT(s.firstName ,' ', s.lastName, s.addressLine1, s.city, s.stateOrProvince, s.postalCode, s.countryCode)),2))
) h (addressCode)
LEFT JOIN #Addresses a ON a.addressCode = h.AddressCode
WHERE a.addressCode IS NULL
)
INSERT INTO #Addresses
(
orderId,
fullName,
addressLine1,
city,
stateOrProvince,
postalCode,
countryCode,
addressCode
)
SELECT orderId,
fullName,
addressLine1,
city,
stateOrProvince,
postalCode,
countryCode,
addressCode
FROM cte
WHERE rn = 1;
Note: If you use CROSS APPLY to calculate the hashcode one avoids calculating it multiple times.

Data population from database as nested array object

I have a table structure as below in SQL Server database,
I want to populate the data from database something similar to JSON like as below:
id: 1
aname: xyz
categories: bus
{
arnam: res
street: [s1,s2]
},
{
arnam: com
street: [c1,c2]
}
Can someone please guide me as to how I can do this in the database using normal SQL query or procedure.
Your json is not valid, but according to your table I think you want to know how to parse data from nested JSON with array of values with this structure:
WITH cte AS (
SELECT * FROM (VALUES
('{"id": 1, "aname": "xyz",
"categories": {
"bus": [
{"aname": "res",
"street": ["c1", "c2"]
},
{"aname": "res",
"street": ["s1", "s2"]
}]
}
}'),
('{"id": 2, "aname": "abc",
"categories": {
"bus": [
{"aname": "foo",
"street": ["c1", "c2"]
},
{"aname": "zoo",
"street": ["s1", "s2"]
}]
}
}')
) t1 ([json])
)SELECT
ROW_NUMBER() OVER(ORDER BY [id]) AS RN,
*
FROM cte AS e
CROSS APPLY OPENJSON(e.[json]) WITH (
[id] int '$.id',
[aname] VARCHAR(100) '$.aname',
[categories_jsn] NVARCHAR(MAX) '$.categories.bus' AS JSON
) AS jsn
CROSS APPLY OPENJSON([categories_jsn]) WITH (
[street_arr] NVARCHAR(MAX) '$.street' AS JSON,
[aname_lvl2] VARCHAR(20) '$.aname'
) AS jsn2
CROSS APPLY OPENJSON([street_arr]) WITH (
[street] VARCHAR(20) '$'
)
Output:

SQL- Merging json with a node name

I have a table with json vaules in nvarchar columns
ID ConfigKey ConfigValue
1 employee {"name":"jhon","age":"23","salary":"5000"}
2 Dept {"name": "Marketing", "code":"12", "manager":"sam"}
3 manager {"managername":"abc", "dept":"AB"}
I need to get merged json for selected ConfiKey by adding ConfigKey value as node name for the ConfigValue and also merged json as below.
For example when i want to get for employee and manager. Output should be like
{
"employee": {
"name": "jhon",
"age": "23",
"salary": "5000"
},
"manager": {
"managername": "abc",
"dept": "AB"
}
}
When I want to get for only ConfigKey value employee output should be
{
"employee": {
"name": "jhon",
"age": "23",
"salary": "5000"
}
}
I tried using JSON_MODIFY but couldn't achieve this. How I can achieve this in SQL query.
You can do this with PIVOT and JSON_QUERY but the code will quickly get messy as you add more ConfigKey rows...
/*
* Setup example type, table and data...
*/
create type ConfigKeyTableType as table (
ConfigKey nvarchar(10)
);
create table dbo.Example (
ID int,
ConfigKey nvarchar(10),
ConfigValue nvarchar(max)
);
insert dbo.Example (ID, ConfigKey, ConfigValue) values
(1, N'employee', N'{"name":"jhon","age":"23","salary":"5000"}'),
(2, N'Dept', N'{"name": "Marketing", "code":"12", "manager":"sam"}'),
(3, N'manager', N'{"managername":"abc", "dept":"AB"}');
go
/*
* Stored procedure to return the JSON based on the supplied ConfigKey values...
*/
create procedure dbo.usp_GetConfigJSON (
#ConfigKeys ConfigKeyTableType readonly
)
as
begin
set nocount on;
select
json_query(dept) as [dept],
json_query(employee) as [employee],
json_query(manager) as [manager]
from (
select Ex.ConfigKey, Ex.ConfigValue
from dbo.Example Ex
join #ConfigKeys keys on keys.ConfigKey=Ex.ConfigKey
) src
pivot (max(ConfigValue) for ConfigKey in ([dept], [employee], [manager])) pvt
for json auto, without_array_wrapper;
end
go
To invoke it from SQL...
declare #ConfigKeys ConfigKeyTableType;
insert #ConfigKeys (ConfigKey) values
(N'employee'),
(N'manager');
exec dbo.usp_GetConfigJSON #ConfigKeys;
go
declare #ConfigKeys ConfigKeyTableType;
insert #ConfigKeys (ConfigKey) values
(N'employee');
exec dbo.usp_GetConfigJSON #ConfigKeys;
go
Which yields the results...
{
"employee": {
"name": "jhon",
"age": "23",
"salary": "5000"
},
"manager": {
"managername": "abc",
"dept": "AB"
}
}
...and...
{
"employee": {
"name": "jhon",
"age": "23",
"salary": "5000"
}
}

Generate nested JSON from stored procedure

I have sample data in a SQL Server table in the following format
CREATE TABLE #tempA
(
HomeId int IDENTITY PRIMARY KEY,
City nvarchar(20),
State nchar(2),
Email VARCHAR(50)
);
INSERT INTO #tempA (City, State, Email)
VALUES ('Cleveland', 'OH', 'sd#aol.com')
INSERT INTO #tempA (City, State, Email)
VALUES ('Malibu', 'CA', 'sd#aol.com')
INSERT INTO #tempA (City, State, Email)
VALUES ('Atlanta', 'GA', 'ploll#aol.com')
SELECT * FROM #tempA
I need a JSON output returned by a stored procedure in the following format, I am trying to group it by email field, I tried using JSON AUTO but not able to achieve in the following format ? Any tips?
[
{
"Email": "sd#aol.com",
"Tasks": [
{
"City": "Cleveland",
"State": "OH"
},
{
"City": "Malibu",
"State": "CA"
}
]
},
{
"Email": "ploll#aol.com",
"Tasks": [
{
"City": "Atlanta",
"State": "GA"
}
]
}
]
One method would be to use a subquery for the State and Email values and group on the email column in the outer query:
SELECT A.Email,
(SELECT B.City,
B.State
FROM #tempA B
WHERE A.Email = B.Email
ORDER BY B.City ASC
FOR JSON AUTO) AS Tasks
FROM #tempA A
GROUP BY A.Email
ORDER BY A.Email DESC
FOR JSON AUTO;
Which gives:
[
{
"Email": "sd#aol.com",
"Tasks": [
{
"City": "Cleveland",
"State": "OH"
},
{
"City": "Malibu",
"State": "CA"
}
]
},
{
"Email": "ploll#aol.com",
"Tasks": [
{
"City": "Atlanta",
"State": "GA"
}
]
}
]

SQL Server - How to transform JSON to Relational database

How can we use SQL to Convert a JSON statement into different tables?
For example we have JSON:
{"table1":
{"Name":"table1","Items":
[{"Id":1,"FirstName":"John",
"LastName":"Wen","Country":"UK",
"PostCode":1234,"Status":false,
"Date":"2018-09-18T08:30:32.91",}]},
"table2":
{"Name":"table2","Items":
[{"Id":1,"Name":"leo",
"StudentId":102,"CreatedDate":"2018-09-18","Location":"USA"}]}}
In the relational database, we will get two tables once the JSON is converted
For example, schema 'Table1':
Id FirstName LastName Country PostCode Status Date
1 John Wen UK 1234 false 2018-09-18T08:30:32.91
And the 'Table2' will look like:
Id Name StudentId CreateDate Location
1 Leo 102 2018-9-18 USA
Could anyone please give any advices on it.
You can do this using openjson and json_value functions. Try the following:
Declare #json nvarchar(max),#table1Items nvarchar(max), #table2Items nvarchar(max)
set #json='{
"table1": {
"Name": "table1",
"Items": [{
"Id": 1,
"FirstName": "John",
"LastName": "Wen",
"Country": "UK",
"PostCode": 1234,
"Status": false,
"Date": "2018-09-18T08:30:32.91"
}, {
"Id": 2,
"FirstName": "John1",
"LastName": "Wen1",
"Country": "UK1",
"PostCode": 12341,
"Status": true,
"Date": "2018-09-15T08:30:32.91"
}]
},
"table2": {
"Name": "table2",
"Items": [{
"Id": 1,
"Name": "leo",
"StudentId": 102,
"CreatedDate": "2018-09-18",
"Location": "USA"
}]
}
}'
set #table1Items=(select value from OpenJSON((select value from OpenJSON(#Json) where [key]='table1')) where [key]='Items')
set #table2Items=(select value from OpenJSON((select value from OpenJSON(#Json) where [key]='table2')) where [key]='Items')
--select for table 1
select JSON_VALUE(val,'$.Id') as ID,
JSON_VALUE(val,'$.FirstName') as FirstName,
JSON_VALUE(val,'$.LastName') as LastName,
JSON_VALUE(val,'$.Country') as Country,
JSON_VALUE(val,'$.PostCode') as PostCode,
JSON_VALUE(val,'$.Status') as Status,
JSON_VALUE(val,'$.Date') as Date
from
(
select value as val from openJSON(#table1Items)
) AS Table1JSON
--select for table 1
select JSON_VALUE(val,'$.Id') as ID,
JSON_VALUE(val,'$.Name') as FirstName,
JSON_VALUE(val,'$.StudentId') as LastName,
JSON_VALUE(val,'$.CreatedDate') as Country,
JSON_VALUE(val,'$.Location') as PostCode
from
(
select value as val from openJSON(#table2Items)
) AS Table2JSON
It is working exactly as you wanted. At the end, the two select statements return the tables as you mentioned. Just add them to your desired table using insert into select. I have also tried adding another object to table1 array and verified that it is working fine i.e. returning two rows for two objects. Hope this helps
If SQL Version 2016+ use OPENJSON AND with_clause:
https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-2017
DECLARE #JsonData NVARCHAR(MAX);
SET #JsonData = N'
{
"table1": {
"Name": "table1",
"Items": [
{
"Id": 1,
"FirstName": "John",
"LastName": "Wen",
"Country": "UK",
"PostCode": 1234,
"Status": false,
"Date": "2018-09-18T08:30:32.91"
},
{
"Id": 2,
"FirstName": "John1",
"LastName": "Wen1",
"Country": "UK1",
"PostCode": 12341,
"Status": true,
"Date": "2018-09-15T08:30:32.91"
}
]
},
"table2": {
"Name": "table2",
"Items": [
{
"Id": 1,
"Name": "leo",
"StudentId": 102,
"CreatedDate": "2018-09-18",
"Location": "USA"
}
]
}
}
';
--Table1
SELECT [a].[Id]
, [a].[FistName]
, [a].[Lastname]
, [a].[Country]
, [a].[PostCode]
, [a].[Status]
, [a].[Date]
FROM
OPENJSON(#JsonData, '$.table1.Items')
WITH (
[Id] INT '$.Id'
, [FistName] NVARCHAR(200) '$.FirstName'
, [Lastname] NVARCHAR(200) '$.LastName'
, [Country] NVARCHAR(200) '$.Country'
, [PostCode] NVARCHAR(200) '$.PostCode'
, [Status] NVARCHAR(200) '$.Status'
, [Date] DATETIME '$.Date'
) [a];
--Table2
SELECT [a].[Id]
, [a].[Name]
, [a].[StudentId]
, [a].[CreatedDate]
, [a].[Location]
FROM
OPENJSON(#JsonData, '$.table2.Items')
WITH (
[Id] INT '$.Id'
, [Name] NVARCHAR(200) '$.Name'
, [StudentId] INT '$.StudentId'
, [CreatedDate] DATETIME '$.CreatedDate'
, [Location] NVARCHAR(200) '$.Location'
) [a];
Try using OPENJSON function in SQL Server:
ReferenceLink_1
ReferenceLink_2