SQL Server OPENJSON read nested json - json

I have some json that I would like to parse in SQL Server 2016. There is a hierarchy structure of Projects->Structures->Properties. I would like to write a query that parses the whole hierarchy but I don't want to specify any elements by index number ie I don't want to do anything like this:
openjson (#json, '$[0]')
or
openjson (#json, '$.structures[0]')
I had this idea that I could read the values of the top level project objects along with the json string that represents the structures below it, which could then be parsed separately. The problem is that the following code does not work:
declare #json nvarchar(max)
set #json = '
[
{
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Project",
"structures":[
{
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Structure",
"BaseStructure":"Base Structure",
"DatabaseSchema":"dbo",
"properties":[
{
"IdProperty":"618DC40B-4D04-4BF8-B1E6-12E13DDE86F4",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 2",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
},
{
"IdProperty":"FFF433EC-0BB5-41CD-8A71-B5F09B97C5FC",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 1",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
}
]
}
]
}
]';
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max)
) as Projects
IdProject and Name get returned no problem but for some reason I cannot get the nested json held in 'structures'. Instead of the json content it just returns NULL:
Does anyone know if this is possible and if so, what am I doing wrong?

Using CROSS APPLY:
declare #json nvarchar(max)
set #json = '
[
{
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Project",
"structures":[
{
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Structure",
"BaseStructure":"Base Structure",
"DatabaseSchema":"dbo",
"properties":[
{
"IdProperty":"618DC40B-4D04-4BF8-B1E6-12E13DDE86F4",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 2",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
},
{
"IdProperty":"FFF433EC-0BB5-41CD-8A71-B5F09B97C5FC",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 1",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
}
]
}
]
}
]';
select
Projects.IdProject, Projects.Name as NameProject,
Structures.IdStructure, Structures.Name as NameStructure, Structures.BaseStructure, Structures.DatabaseSchema,
Properties.*
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) as json
)
as Projects
cross apply openjson (Projects.structures)
with
(
IdStructure uniqueidentifier,
Name nvarchar(100),
BaseStructure nvarchar(100),
DatabaseSchema sysname,
properties nvarchar(max) as json
) as Structures
cross apply openjson (Structures.properties)
with
(
IdProperty uniqueidentifier,
NamePreoperty nvarchar(100) '$.Name',
DataType int,
[Precision] int,
[Scale] int,
IsNullable bit,
ObjectName nvarchar(100),
DefaultType int,
DefaultValue nvarchar(100)
)
as Properties

If you reference JSON object or array you need to specify AS JSON clause:
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) AS JSON
) as Projects
See FAQ: https://learn.microsoft.com/en-us/sql/relational-databases/json/solve-common-issues-with-json-in-sql-server?view=sql-server-ver15#return-a-nested-json-sub-object-from-json-text-with-openjson
If you want to apply OPENJSON on the returned structures array, you can use something like following code:
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) AS JSON
) as Projects
CROSS APPLY OPENJSON (structures) WITH (......)

Typical! I found the answer just after posting the question. You need to use the 'as json' key word when specifying the columns to return:
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) as json
) as Projects

Related

How to read a complex json array with SQL Server

This is my query:
SELECT
JSON_QUERY(MyStringColumnWithJson, '$.Images') AS images
FROM MyTable
which returns a single field with the JSON data shown here below:
"{
"Images":
[
{"Name":"test1.jpeg","Description":"originalName1.jpeg"},
{"Name":"test2.jpeg","Description":"originalName2.jpeg"},
{"Name":"test3.jpeg","Description":"originalName3.jpeg"}
]
}"
How can I read the images result row by row into a temporary table structure?
Use OPENJSON which returns a data set, not JSON_VALUE, which returns a scalar value. For example:
DECLARE #JSON nvarchar(MAX) = N'{
"Images":
[
{"Name":"test1.jpeg","Description":"originalName1.jpeg"},
{"Name":"test2.jpeg","Description":"originalName2.jpeg"},
{"Name":"test3.jpeg","Description":"originalName3.jpeg"}
]
}';
SELECT *
FROM OPENJSON(#JSON, '$.Images')
WITH (Name nvarchar(128),
Description nvarchar(128))OJ;
SELECT I.[Name],
I.Description
FROM MyTable MT
CROSS APPLY OPENJSON(MT.YourJsonColumn, '$.Images')
WITH (Name nvarchar(128),
Description nvarchar(128)) I;

Reading mulitple json array into rows in SQL Server

Given the sample json data below, how can I write a query to pull the array data all in one step to individual column?
DECLARE #json NVARCHAR(MAX);
SET #json = N'{
"Title":"ReportExport",
"Attachment":"",
"Name":"Dhoni",
"FirstTextArea":"Dhoni",
"Radio":"First",
"CheckBox":"{C++~.Net}",
"FileUpload":"",
"FirstGroupitem":[
{
"Address":"QTUvNU55THBxT2hmVXFkWGpia2NJQT09",
"Age":"30",
"TestField":"",
"Country":"ind",
"SecondTextArea":"11"
},
{
"Address":"OVpuaXpxNTlrZWg4dGI4VXRYMUg0Zz09",
"Age":"30",
"TestField":"",
"Country":"us",
"SecondTextArea":"22"
},
{
"Address":"WGErNFU2S0tYekdsRWZTT2NxSzZLQT09",
"Age":"30",
"TestField":"",
"Country":"us",
"SecondTextArea":"33"
}
],
"SecondGroupitem":[
{
"Address1":"QTUvNU55THBxT2hmVXFkWGpia2NJQT09",
"Age1":"30"
},
{
"Address1":"OVpuaXpxNTlrZWg4dGI4VXRYMUg0Zz09",
"Age1":"30"
}
]
}';
Statement:
SELECT i.Title,i.Attachment,i.Name,i.FirstTextArea,i.Radio,i.CheckBox,i.FileUpload,'FirstGroupitem' as FirstGroupitem,
a.Address, a.Age,a.TestField,a.Country,a.SecondTextArea
FROM OPENJSON(#json)
WITH (
Title VARCHAR(max) N'$.Title',
Attachment VARCHAR(max) N'$.Attachment',
Name VARCHAR(max) N'$.Name',
FirstTextArea VARCHAR(max) N'$.FirstTextArea',
Radio VARCHAR(max) N'$.Radio',
CheckBox VARCHAR(max) N'$.CheckBox',
FileUpload VARCHAR(max) N'$.FileUpload',
FirstGroupitem nvarchar(max) '$.FirstGroupitem' AS JSON
) AS i
CROSS APPLY (
SELECT *
FROM OPENJSON(i.FirstGroupitem)
WITH (
Address VARCHAR(max) N'$.Address',
Age VARCHAR(max) N'$.Age',
TestField VARCHAR(max) N'$.TestField',
Country VARCHAR(max) N'$.Country',
SecondTextArea VARCHAR(max) N'$.SecondTextArea'
)
) a
I want output like this:
You need to join the items from the $.FirstGroupitem" and $."SecondGroupitem JSON arrays by index:
Statement:
SELECT
i.Title, i.Attachment, i.Name, i.FirstTextArea, i.Radio, i.CheckBox,
j.FirstGroupAddress, j.SecondGroupAddress
FROM OPENJSON(#json)
WITH (
Title VARCHAR(max) N'$.Title',
Attachment VARCHAR(max) N'$.Attachment',
Name VARCHAR(max) N'$.Name',
FirstTextArea VARCHAR(max) N'$.FirstTextArea',
Radio VARCHAR(max) N'$.Radio',
CheckBox VARCHAR(max) N'$.CheckBox',
FileUpload VARCHAR(max) N'$.FileUpload',
FirstGroupitem nvarchar(max) '$.FirstGroupitem' AS JSON,
SecondGroupitem nvarchar(max) '$.SecondGroupitem' AS JSON
) AS i
OUTER APPLY (
SELECT f2.Address AS FirstGroupAddress, s2.Address AS SecondGroupAddress
FROM OPENJSON (i.FirstGroupitem) f1
FULL JOIN OPENJSON (i.SecondGroupitem) s1 ON f1.[key] = s1.[key]
OUTER APPLY OPENJSON(f1.[value]) WITH (
Address varchar(100) '$.Address'
-- Additional columns here
) f2
OUTER APPLY OPENJSON(s1.[value]) WITH (
Address varchar(100) '$.Address1'
-- Additional columns here
) s2
) j
Result:
Title Attachment Name FirstTextArea Radio CheckBox FirstGroupAddress SecondGroupAddress
---------------------------------------------------------------------------------------------------------------------------------
ReportExport Dhoni Dhoni First {C++~.Net} QTUvNU55THBxT2hmVXFkWGpia2NJQT09 QTUvNU55THBxT2hmVXFkWGpia2NJQT09
ReportExport Dhoni Dhoni First {C++~.Net} OVpuaXpxNTlrZWg4dGI4VXRYMUg0Zz09 OVpuaXpxNTlrZWg4dGI4VXRYMUg0Zz09
ReportExport Dhoni Dhoni First {C++~.Net} WGErNFU2S0tYekdsRWZTT2NxSzZLQT09

Dealing with special characters in SQL OPENJSON WITH command?

I have a JSON string that I am trying to import into my SQL Server database using the OPENJSON WITH but I am having issues because I think the JSON "field names" contain a forward slash.
What else would I need to do in order to get the start and end values? At the moment I just get NULLS...
DECLARE #JSONText NVarChar(max) = '[{
"Labour Resource Name": "ABC Consulting",
"Start Date/Time": "2020-07-06T06:30:00",
"End Date/Time": "2020-07-06T10:30:00"
}]'
SELECT *
FROM OPENJSON (#JSONText)
WITH ([Labour Resource Name] NVarChar(512),
[Start Date/Time] NVarChar(50),
[End Date/Time] NVarChar(50)
)
You don't have to mangle your output column aliases, instead you can specify JSON paths for all of them:
DECLARE #JSONText NVarChar(max) = '[{
"Labour Resource Name": "ABC Consulting",
"Start Date/Time": "2020-07-06T06:30:00",
"End Date/Time": "2020-07-06T10:30:00"
}]';
SELECT j.*
FROM OPENJSON (#JSONText)
WITH (
[LabourResourceName] nvarchar(512) '$."Labour Resource Name"',
[StartDateTime] nvarchar(50) '$."Start Date/Time"',
[EndDateTime] nvarchar(50) '$."End Date/Time"'
) j;
DECLARE #JSONText NVarChar(max) = '[{
"Labour Resource Name": "ABC Consulting",
"Start Date/Time": "2020-07-06T06:30:00",
"End Date/Time": "2020-07-06T10:30:00"
}]'
SELECT *
FROM OPENJSON (REPLACE(#JSONText, N'Date/Time', N'Date\/Time'))
WITH ([Labour Resource Name] NVarChar(512),
[Start Date/Time] NVarChar(50),
[End Date/Time] NVarChar(50)
)
Wrap the json field name in double quotes:
Before:
ecommerce nvarchar(max) '$.special-characters',
After:
ecommerce nvarchar(max) '$."special-characters"',

Parse JSON in Microsoft SQL

I have the following JSON,
And I have no clue as to how to parse "Value" (When you run it in SQL you get 3 columns key, value and type)
Any ideas?
DECLARE #json NVARCHAR(MAX);
SET #json = N'[
{"salesDate":"2020-03-02","storeSales":[
{"storeId":"104","sales":[
{"productId":"20002","salesVolume":0.700,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"74301","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"642401","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"784001","salesVolume":2.100,"salesQuantity":3,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1013801","salesVolume":1.500,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1202801","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1209901","salesVolume":0.700,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"1282201","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"3317301","salesVolume":1.500,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"4801301","salesVolume":0.700,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"5780106","salesVolume":6.000,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"7964902","salesVolume":0.375,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"10785001","salesVolume":0.750,"salesQuantity":1,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}},
{"productId":"11037501","salesVolume":1.500,"salesQuantity":2,"lastChanged":{"date":"2020-03-03","time":"07:28:06"}}]}]}]';
SELECT *
FROM OPENJSON(#json)
Assuming you wanted to get the sales data try this (although I am not 100% sure if this query offers the best performance)
SELECT [SalesDate], [StoreId], [ProductId], [SalesVolume], [SalesQuantity]
FROM OPENJSON(#json) WITH (
[SalesDate] DATETIME '$.salesDate',
[StoreSales] NVARCHAR(MAX) '$.storeSales' AS JSON
)
OUTER APPLY OPENJSON(StoreSales) WITH (
[StoreId] INT '$.storeId',
[Sales] NVARCHAR(MAX) '$.sales' AS JSON
)
OUTER APPLY OPENJSON(Sales) WITH (
[ProductId] INT '$.productId',
[SalesVolume] DECIMAL(18, 4) '$.salesVolume',
[SalesQuantity] INT '$.salesQuantity'
)
Value is the first object in your JSON array, which is itself another JSON object. SO you will have to read it using other SQL Server JSON utilities. For example:
SELECT JSON_VALUE(Value, '$.salesDate')
FROM OPENJSON(#json)

Extract data from Json string and divide into multiple columns

I have a column in a table that has Jsonstring text:
[
{
"PType":{"code":"9","name":"Hospitality"},
"PSubType":{"code":"901","name":"Hotel"},
"AType":{"code":"9","name":"Hospitality"},
"ASubType":{"code":"901","name":"Hotel"}
}
]
How can I divide that into multiple columns using sql server query?
With SQL-Server 2016+ there is native JSON support:
DECLARE #json NVARCHAR(MAX)=
N'[
{
"PType":{"code":"9","name":"Hospitality"},
"PSubType":{"code":"901","name":"Hotel"},
"AType":{"code":"9","name":"Hospitality"},
"ASubType":{"code":"901","name":"Hotel"}
}
]';
SELECT A.[key]
,JSON_VALUE(A.value,'$.code') AS Code
,JSON_VALUE(A.value,'$.name') AS [Name]
FROM OPENJSON(JSON_QUERY(#json,'$[0]')) A;
The result
key Code Name
---------------------------------
PType 9 Hospitality
PSubType 901 Hotel
AType 9 Hospitality
ASubType 901 Hotel
Some explanation:
With JSON_QUERY() you can get the element within the array, OPENJSON will find all objects within and return them as derived table.
JSON_VALUE will read the internals into columns.
Hint
with a version below v2016 you should use another tool or think about a CLR function...
In SQL Server 2016+ you can use a combination of openjson (more info here) and cross apply:
declare #json nvarchar(max) = '[ { "PType":{"code":"9","name":"Hospitality"}, "PSubType":{"code":"901","name":"Hotel"}, "AType":{"code":"9","name":"Hospitality"}, "ASubType":{"code":"901","name":"Hotel"} } ]'
select
[PT].[code] as Ptype_Code
,[PT].[name] as Ptype_Name
,[PS].[code] as PSubType_Code
,[PS].[name] as PSubType_Name
,[AT].[code] as AType_Code
,[AT].[name] as AType_Name
,[AS].[code] as ASubType_Code
,[AS].[name] as ASubType_Name
from openjson (#json)
with
(
PType nvarchar(max) as json,
PSubType nvarchar(max) as json,
AType nvarchar(max) as json,
ASubType nvarchar(max) as json
) as lev1
cross apply openjson (lev1.PType)
with
(
code int,
name nvarchar(100)
) as PT
cross apply openjson (lev1.PSubType)
with
(
code int,
name nvarchar(100)
) as PS
cross apply openjson (lev1.AType)
with
(
code int,
name nvarchar(100)
) as [AT]
cross apply openjson (lev1.ASubType)
with
(
code int,
name nvarchar(100)
) as [AS]
Result: