Referring to the example provided by Microsoft:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 },
{ "id" : 5,"info": { "name": "Jane", "surname": "Smith" }, "dob": "2005-11-04T12:00:00" }
]'
SELECT *
FROM OPENJSON(#json)
WITH (id int 'strict $.id',
firstName nvarchar(50) '$.info.name', lastName nvarchar(50) '$.info.surname',
age int, dateOfBirth datetime2 '$.dob')
when the JSON data has an array inside, for example:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{ "id" : 2,"info": { "name": "John", "surname": "Smith" },
"Phones": ["123","345","678"] // like here
}
]'
Is there any way to join the array on the parsed data to get something like this:
Id First Name Last Name Phone
2 John Smith 123
2 John Smith 345
2 John Smith 678
OUTER APPLY is your friend here. Let's mix up both kinds of rows for good measure.
DECLARE #json NVARCHAR(MAX)
SET #json = N'
[
{
"id": 2,
"info": {
"name": "John",
"surname": "Smith"
},
"age": 25,
"Phones": [
"123",
"345",
"678"
]
},
{
"id": 5,
"info": {
"name": "Jane",
"surname": "Smith"
},
"dob": "2005-11-04T12:00:00"
}
]'
SELECT id, [name], [surname], age, dateOfBirth, number
FROM (
SELECT *
FROM OPENJSON(#json)
WITH (
id INT 'strict $.id',
[name] NVARCHAR(50) '$.info.name',
[surname] NVARCHAR(50) '$.info.surname',
age INT,
dateOfBirth DATETIME2 '$.dob',
Phones NVARCHAR(MAX) AS JSON
)
) AS people
OUTER APPLY OPENJSON(Phones)
WITH (
number NVARCHAR(50) '$'
)
Result:
+----+------+---------+------+-----------------------------+--------+
| id | name | surname | age | dateOfBirth | number |
+----+------+---------+------+-----------------------------+--------+
| 2 | John | Smith | 25 | NULL | 123 |
| 2 | John | Smith | 25 | NULL | 345 |
| 2 | John | Smith | 25 | NULL | 678 |
| 5 | Jane | Smith | NULL | 2005-11-04 12:00:00.0000000 | NULL |
+----+------+---------+------+-----------------------------+--------+
Well, you can always do something like this:
SELECT ID, FirstName, LastName, value
FROM OPENJSON(#json)
WITH(ID int '$.id',
FirstName nvarchar(50) '$.info.name',
LastName nvarchar(50) '$.info.surname',
Phones nvarchar(max) '$.Phones' AS Json)
CROSS APPLY OPENJSON(Phones)
Hope this helps.
You will have to do it in two passes:
Extract for each person data and leaving array of phone numbers as JSON
Use CROSS/OUTER APPLY to parse array of phone numbers for each person and join result together
Something like this:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "Phones": ["123","345","678"] },
{ "id" : 3,"info": { "name": "Jane", "surname": "Smith" }, "Phones": ["321","543"] }
]';
WITH CTE AS (
SELECT id, firstName, lastName, phones
FROM OPENJSON(#json)
WITH (
id INT 'strict $.id',
firstName NVARCHAR(50) '$.info.name',
lastName NVARCHAR(50) '$.info.surname',
phones NVARCHAR(MAX) '$.Phones' AS JSON
)
)
SELECT c.id, c.firstName, c.lastName, p.value as phone
FROM CTE c
CROSS APPLY OPENJSON(c.phones) p
You can use C# library
https://www.dotnet4techies.com/2018/07/convert-json-to-sql-format-using-csharp.html
It is a powerful tool and it maintains sql relationships from your Json if it has nested levels.
Related
I try to parse JSON with the function OPENJSON with a CROSS APLY but I have some problems.
My Json is like this:
[
{
"Communications":[
{
"ID_Communication":null,
"CommunicationType":"HOME",
"CommunicationValue":"0602060206",
"Priority":0,
"Disabled":false
},
{
"ID_Communication":null,
"CommunicationType":"MOBILE",
"CommunicationValue":"0602060306",
"Priority":0,
"Disabled":false
},
{
"ID_Communication":null,
"CommunicationType":"EMAIL",
"CommunicationValue":"MONEMAIL#EMAIL.FR",
"Priority":0,
"Disabled":false
}
],
"InternalId":23126,
"ExternalId":"",
"LastUpdateDate":"2020-01-05T12:04:53",
"Type1":{
"Id":1
},
"Type2":{
"Id":2
},
"Type3":null,
"Title":{
"Id":1
},
"LastName":"TOTO",
"FirstName":"TITI",
"OrganizationName":"",
"Sex":"M",
"BirthDate":"1959-10-07T00:00:00",
"Adresses":[
{
"ID_Address":null,
"Address1":"1 RUE DE FRANCE",
"Address2":"",
"Address3":"",
"Address4":null,
"ZipCode":"94500",
"CityName":"MA VILLE",
"Country":{
"Id":"FR"
},
"Type":null,
"State":null,
"Priority":0,
"ScopeId":0
}
],
"Language":{
"Id":"FR"
},
"Comment":"",
"PassportNumber":"",
"IdentityCardNumber":"",
"Nationality":null,
"SocialGroup":{
"Id":1
},
"OptIns":[
{
"OptInType":"OPT_CLUB",
"OptInLabel":"Optin club",
"OptInValue":0
},
{
"OptInType":"OPT_PART",
"OptInLabel":"Optin partenaires",
"OptInValue":0
}
],
"WebLogin":"MONEMAIL#EMAIL.FR"
}
]
I have try a query like this:
This Query try to get differents informations about this JSON.
declare #JSON_CONTACT nvarchar(MAX)
SELECT #JSON_CONTACT = '[
{
"Communications":[
{
"ID_Communication":null,
"CommunicationType":"HOME",
"CommunicationValue":"0602060206",
"Priority":0,
"Disabled":false
},
{
"ID_Communication":null,
"CommunicationType":"MOBILE",
"CommunicationValue":"0602060306",
"Priority":0,
"Disabled":false
},
{
"ID_Communication":null,
"CommunicationType":"EMAIL",
"CommunicationValue":"MONEMAIL#EMAIL.FR",
"Priority":0,
"Disabled":false
}
],
"InternalId":23126,
"ExternalId":"",
"LastUpdateDate":"2020-01-05T12:04:53",
"Type1":{
"Id":1
},
"Type2":{
"Id":2
},
"Type3":null,
"Title":{
"Id":1
},
"LastName":"TOTO",
"FirstName":"TITI",
"OrganizationName":"",
"Sex":"M",
"BirthDate":"1959-10-07T00:00:00",
"Adresses":[
{
"ID_Address":null,
"Address1":"1 RUE DE FRANCE",
"Address2":"",
"Address3":"",
"Address4":null,
"ZipCode":"94500",
"CityName":"MA VILLE",
"Country":{
"Id":"FR"
},
"Type":null,
"State":null,
"Priority":0,
"ScopeId":0
}
],
"Language":{
"Id":"FR"
},
"Comment":"",
"PassportNumber":"",
"IdentityCardNumber":"",
"Nationality":null,
"SocialGroup":{
"Id":1
},
"OptIns":[
{
"OptInType":"OPT_CLUB",
"OptInLabel":"Optin club",
"OptInValue":0
},
{
"OptInType":"OPT_PART",
"OptInLabel":"Optin partenaires",
"OptInValue":0
}
],
"WebLogin":"MONEMAIL#EMAIL.FR"
}
]'
DROP TABLE TEMP_JSON_RCT_TEST_PARSE
SELECT *
INTO TEMP_JSON_RCT_TEST_PARSE
FROM OPENJSON (#JSON_CONTACT)
WITH (
FIRSTNAME nvarchar(50) '$.FirstName',
LASTNAME nvarchar(50) '$.LastName',
Sex nvarchar(2) '$.Sex',
BirthDate date '$.BirthDate',
Communications nvarchar(max) AS JSON
) AS Communications
CROSS APPLY OPENJSON(Communications)
WITH (
CommunicationType nvarchar(50),
CommunicationValue nvarchar(50),
Adresses nvarchar(max) AS JSON
) AS Adresses
CROSS APPLY OPENJSON(Adresses)
WITH (
Address1 nvarchar(100)
)
I would like my select return:
FIRSTNAME, LASTNAME, SEX, BIRTHDATE, EMAIL, MOBILE, HOME, LASTUPDATEDATE, ADDRESS1, ADRESSE2, ADDRESSE3, ADDRESS4, ZIPCODE, CITYNAME, OPT_CLUB, OPT_PART
VALUES:
MY FIRSTNAME, MYLASTNAME, M, 09/05/1989, MONEMAIL#EMAIL.FR, 0602060306,0602060206, 2020-01-05T12:04:53, 1 RUE DE FRANCE, , , , 94500, MA VILLE, 0, 0
When I execute my query, that return null, I don't understand why.
Can you help about this ?
This seems to return your expected results, but note that this works only if OptIns and Communications JSON arrays has the structure in the question. You need to use OPENJSON() with explicit schema and AS JSON clause for nested JSON arrays:
SELECT
FIRSTNAME, LASTNAME, SEX, BIRTHDATE,
EMAIL, MOBILE, HOME,
LASTUPDATEDATE, ADDRESS1, ADDRESS2, ADDRESS3, ADDRESS4, ZIPCODE, CITYNAME,
OPT_CLUB, OPT_PART
FROM OPENJSON(#JSON_CONTACT, '$') WITH (
FIRSTNAME nvarchar(100) '$.FirstName',
LASTNAME nvarchar(100) '$.LastName',
SEX nvarchar(1) '$.Sex',
BIRTHDATE nvarchar(100) '$.BirthDate',
Communications nvarchar(max) '$.Communications' AS JSON,
Adresses nvarchar(max) '$.Adresses' AS JSON,
LASTUPDATEDATE nvarchar(100) '$.LastUpdateDate',
OptIns nvarchar(max) '$.OptIns' AS JSON
) j1
CROSS APPLY (
SELECT
MAX(CASE WHEN CommunicationType = 'EMAIL' THEN CommunicationValue END) AS EMAIL,
MAX(CASE WHEN CommunicationType = 'MOBILE' THEN CommunicationValue END) AS MOBILE,
MAX(CASE WHEN CommunicationType = 'HOME' THEN CommunicationValue END) AS HOME
FROM OPENJSON(j1.Communications) WITH (
CommunicationType nvarchar(100) '$.CommunicationType',
CommunicationValue nvarchar(100) '$.CommunicationValue'
)
) j2
CROSS APPLY OPENJSON(j1.Adresses) WITH (
ADDRESS1 nvarchar(100) '$.Address1',
ADDRESS2 nvarchar(100) '$.Address2',
ADDRESS3 nvarchar(100) '$.Address3',
ADDRESS4 nvarchar(100) '$.Address4',
ZIPCODE nvarchar(100) '$.ZipCode',
CITYNAME nvarchar(100) '$.CityName'
) j3
CROSS APPLY (
SELECT
MAX(CASE WHEN OptInType = 'OPT_CLUB' THEN OptInValue END) AS OPT_CLUB,
MAX(CASE WHEN OptInType = 'OPT_PART' THEN OptInValue END) AS OPT_PART
FROM OPENJSON(j1.OptIns) WITH (
OptInType nvarchar(100) '$.OptInType',
OptInValue int '$.OptInValue'
)
) j4
Result (with the JOSN in the question):
FIRSTNAME LASTNAME SEX BIRTHDATE EMAIL MOBILE HOME LASTUPDATEDATE ADDRESS1 ADDRESS2 ADDRESS3 ADDRESS4 ZIPCODE CITYNAME OPT_CLUB OPT_PART
TITI TOTO M 1959-10-07T00:00:00 MONEMAIL#EMAIL.FR 0602060306 0602060206 2020-01-05T12:04:53 1 RUE DE FRANCE 94500 MA VILLE 0 0
Address is part of main entity
SELECT *
FROM OPENJSON (#JSON_CONTACT)
WITH (
FIRSTNAME nvarchar(50) '$.FirstName',
LASTNAME nvarchar(50) '$.LastName',
Sex nvarchar(2) '$.Sex',
BirthDate date '$.BirthDate',
Communications nvarchar(max) AS JSON,
Adresses nvarchar(max) AS JSON
) AS Communications
CROSS APPLY OPENJSON(Communications)
WITH (
CommunicationType nvarchar(50),
CommunicationValue nvarchar(50)
) AS Adresses
CROSS APPLY OPENJSON(Adresses)
WITH (
Address1 nvarchar(100)
)
I have some json like this:
SET #json =N'[
{ "id" : 2,"name": "John", "surname": "Smith", "lastname":"", "age": 25 },
]'
I need to insert into table with a condition like IF LASTNAME IS EMPTY IN JSON THEN INSERT SURNAME INTO LASTNAME ELSE INSERT LASTNAME INTO LASTNAME
insert into mytable (id,firstname,lastname,age)
select id,name,case statement,age from openjson
WITH (id int 'strict $.id',name nvarchar(100) '$.name',case statement, age int '$.age');
Hi i think this query can respond :
DECLARE #json varchar(MAX)
SET #json =N'[
{ "id" : 2,"name": "John", "surname": "Smith", "lastname":"", "age": 25 },
{ "id" : 2,"name": "John", "surname": "Smith", "lastname":"TT", "age": 25 },
{ "id" : 2,"name": "John", "surname": "Smith", "lastname":"TEST", "age": 25 }
]'
select id,name,case when lastname = '' then surname else lastname end as lastnameup, age from openjson(#json)
WITH (id int 'strict $.id',name nvarchar(100) '$.name', surname nvarchar(100) '$.surname', lastname nvarchar(100) '$.lastname', age int '$.age');
EDIT for surname propose thanks to #Shnugo
If I do this I can get the first value in the array. But how can I get all of the values in the list ?
SELECT
JSON_VALUE('{"Distributor": [5030, 4000, 1231]}', '$.Distributor[0]') AS result;
SELECT value
FROM OPENJSON('{"Distributor": [5030, 4000, 1231]}','$.Distributor')
'$.Distributor' is the 'start path' to start looking for an array
You can take look at this article:
https://learn.microsoft.com/fr-fr/sql/relational-databases/json/json-data-sql-server?view=sql-server-2017
Using function Openjson and Outer apply
Example provided:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 },
{ "id" : 5,"info": { "name": "Jane", "surname": "Smith", "skills": ["SQL", "C#", "Azure"] }, "dob": "2005-11-04T12:00:00" }
]'
SELECT *
FROM OPENJSON(#json)
WITH (id int 'strict $.id',
firstName nvarchar(50) '$.info.name', lastName nvarchar(50) '$.info.surname',
age int, dateOfBirth datetime2 '$.dob',
skills nvarchar(max) '$.info.skills' as json)
outer apply openjson( skills )
with ( skill nvarchar(8) '$' )
EDIT Code with provided json :
DECLARE #json NVARCHAR(MAX)
SET #json = N'{"Distributor": [5030, 4000, 1231]}'
SELECT Distributor
FROM OPENJSON(#json)
WITH (Distributors nvarchar(max) '$.Distributor' as json)
outer apply openjson( Distributors )
with ( Distributor int '$' )
RESULT :
Distributor
5030
4000
1231
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
I have a table called DimCompany in SQL Server like so:
+----+---------+--------+
| id | Company | Budget |
+----+---------+--------+
| 1 | abc | 111 |
| 2 | def | 444 |
+----+---------+--------+
I would like to convert this table into a json file like so:
{
"DimCompany":{
"id":1,
"companydetails": [{
"columnid": "1",
"columnfieldname": "Company",
"columnfieldvalue: "abc"
}
{
"columnid": "2",
"columnfieldname": "Budget",
"columnfieldvalue: "111"
}]
}
},
{
"DimCompany":{
"id":2,
"companydetails": [{
"columnid": "1",
"columnfieldname": "Company",
"columnfieldvalue: "def"
}
{
"columnid": "2",
"columnfieldname": "Budget",
"columnfieldvalue: "444"
}]
}
}
where columnid is a value from sys.columns against the column field name. I've tried doing this by unpivoting the table and joining sys.columns on fieldname where sys.objects.name=DimCompany and putting this in a view, then querying on the view to get json output for migration into DocumentDB.
However I would like to not use unpivot and just directly form a query to get desired output.
I'm just curious whether this is possible in SQL server or in any other tool.
Without using UNPIVOT and doing it yourself, the following SQL:
if object_id(N'dbo.DimCompany') is not null drop table dbo.DimCompany;
create table dbo.DimCompany (
id int not null identity(1,1),
Company nvarchar(50) not null,
Budget float not null
);
insert dbo.DimCompany (Company, Budget) values
('abc', 111),
('def', 444);
go
select id as 'DimCompany.id',
(
select columnid=cast(sc.column_id as nvarchar), columnfieldname, columnfieldvalue
from (
select N'Company', Company from dbo.DimCompany DC2 where DC2.id = DC1.id
union
select N'Budget', cast(Budget as nvarchar) from dbo.DimCompany DC2 where DC2.id = DC1.id
) keyValues (columnfieldname, columnfieldvalue)
join sys.columns sc on sc.object_id=object_id(N'dbo.DimCompany') and sc.name=columnfieldname
for json path
) as 'DimCompany.companydetails'
from dbo.DimCompany DC1
for json path, without_array_wrapper;
Produces the following JSON as per your example:
{
"DimCompany": {
"id": 1,
"companydetails": [
{
"columnid": "2",
"columnfieldname": "Company",
"columnfieldvalue": "abc"
},
{
"columnid": "3",
"columnfieldname": "Budget",
"columnfieldvalue": "111"
}
]
}
},
{
"DimCompany": {
"id": 2,
"companydetails": [
{
"columnid": "2",
"columnfieldname": "Company",
"columnfieldvalue": "def"
},
{
"columnid": "3",
"columnfieldname": "Budget",
"columnfieldvalue": "444"
}
]
}
}
Things to note:
The sys.columns columnid values start at 1 for the dbo.DimCompany.id column. Subtract 1 before casting if that's a requirement.
Using without_array_wrapper removes the surrounding [] characters, per your example, but isn't really valid JSON as a result.
I doubt this would be scalable for tables with large numbers of columns.