My business requirement is to store lists of issues & responses as JSON data within a SQL Server 2019 table. Each list corresponds to a page within a document. At minimum, I’d like to be able to retrieve the GUID for a page and its entire list (one row per issue/response). So far, I’ve only been able to return a single page’s list OR its GUID. I’ve tried manipulating the JSON path (both in the OPENJSON function and in its WITH schema description), but I’ve only gotten NULL values for anything past the first level of objects in the Pages array.
JSON:
{
"Pages": [
{
"DocumentTemplatePageId": "F472F93F-F36B-1410-8C7C-006D55A93A8F",
"DocumentTemplatePageTypeId": 9,
"PageData": {
"IssuesList": [
{
"IssueOrderNumber": 1,
"Description": "Houston, we have a problem.",
"Resolution": "We are working on it."
},
{
"IssueOrderNumber": 2,
"Description": "We have issues with employee retention.",
"Resolution": "We will start giving retention bonuses."
}
]
}
},
{
"DocumentTemplatePageId": "EB72F93F-F36B-1410-8C7C-006D55A93A8F",
"DocumentTemplatePageTypeId": 9,
"PageData": {
"IssuesList": [
{
"IssueOrderNumber": 1,
"Description": "We have issues with including all the legalese in our advertising.",
"Resolution": "We will contract to have an editor review all advertising."
},
{
"IssueOrderNumber": 2,
"Description": "Sales opportunities are lost due to missed callbacks.",
"Resolution": "We will schedule a dedicated hour within the day for callbacks."
}
]
}
},
{
"DocumentTemplatePageId": "BA82B33F-F36B-1410-8C7C-006D55A93A8F",
"DocumentTemplatePageTypeId": 9,
"PageData": {
"IssuesList": [
{
"IssueOrderNumber": 1,
"Description": "We have issues with hazardous materials storage.",
"Resolution": "We will schedule more frequent pickups for hazardous materials."
},
{
"IssueOrderNumber": 2,
"Description": "We have issues with exhaust fumes in the service area.",
"Resolution": "We will upgrade our venting equipment for the service area."
}
]
}
}
]
}
SQL (returns only a single page’s list, and no page GUID):
DECLARE @templateid NVARCHAR(40) = 'B282B33F-F36B-1410-8C7C-006D55A93A8F'
DECLARE @companyid NVARCHAR(40) = '5A3CDE59-6D80-4E0E-A413-0E91DD24A352'
DECLARE @morejson NVARCHAR(MAX) = (
SELECT JsonData
FROM dbo.[CompanyxDocumentTemplate] WITH (NOLOCK)
WHERE DocumentTemplateId = @templateid
AND CompanyId = @companyid
)
SELECT *
FROM OPENJSON( @morejson, '$.Pages[0].PageData.IssuesList' )
WITH (
[IssueOrderNumber] INT '$.IssueOrderNumber',
[Description] NVARCHAR(250) '$.Description',
[Resolution] NVARCHAR(250) '$.Resolution'
);
Results:
As you can see, I’m having to include the index of the Pages array; not cool, but I could live with having to loop over the array if necessary. I’ve read through the online Microsoft documentation on JSON data, but it hasn’t helped me in dealing with the nested arrays in my JSON.
Thanks in advance for your help!
2
Answers
I think this is what you’re after.
If you’ve got nested arrays, you need to call
openjson
repeatedly on that array until you get down to the level of data you need. Here, I’ve shredded the top levelpage
key and grabbed the$.PageData.IssueList
key. One moreopenjson
call on the value from that call, and you get down to the level you’re interested in.db<>fiddle
For every nested array, you need to correlate using
CROSS APPLY OPENJSON
again to shred that new level. EachOPENJSON
can only refer to either a single level, or even with a custom path then only to a single array index.Any whole JSON objects or arrays must be pulled out using
nvarchar(max) AS JSON
otherwise it will null out.Note how even the original table can be correlated, an intermediate variable is not needed.
db<>fiddle