Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse nested JSON array using SQL Server

I am currently able to parse most of a JSON file using SQL Server's OPENJSON WITH (... syntax. However, this particular file contains nested arrays which I do not know how to handle.

Many of the examples I read reference JSON as a variable. In this case I am calling a file:

select DEV_JSON.*
from OPENROWSET
(BULK 'C:\Users\Myuser\Documents\JSON_extract.json', SINGLE_CLOB) as my_datafile
 CROSS APPLY OPENJSON(BulkColumn) 
WITH
  (DOC_ID           varchar(100)  '$.doc._id',
   DOC_REV          varchar(45)   '$.doc._rev',
   DELY_APPL_NAME   varchar(20)   '$.doc.delivery.application',
   DELY_SENT_BY     varchar(25)   '$.doc.delivery.sender.id',
   DELY_SENT_TYPO   varchar(20)   '$.doc.delivery.sender.type',
   .....
   ....
   ...
   ..) as DEV_JSON

One of the attributes contains a nested array. Below I have copied the 1st 5 attributes of my JSON, as well as the nested "recipients" array.

How do I structure my SQL to parse this section?

"doc": {
    "_id": "[email protected]",
    "_rev": "3-e119db13dae8d50ae0c4579ba9c87fc9",
    "delivery": {
        "application": "App_XYZ",
        "sender": {
            "id": "[email protected]",
            "type": "user"
        },
        "recipients": [{
                "type": "email",
                "recipient": "\"Artzer, Daniel J\" <[email protected]>",
                "sentTS": "2017-10-18T13:04:00.133Z"
            },
            {
                "type": "email",
                "recipient": "\"Higgins, Laura L\" <[email protected]>",
                "sentTS": "2017-10-18T13:04:00.133Z"
            },
            {
                "type": "email",
                "recipient": "\"Friedman, Brian\" <[email protected]>",
                "sentTS": "2017-10-18T13:04:00.133Z"
            },
            {
                "type": "email",
                "recipient": "\"Garcia, Charlie M\" <[email protected]>",
                "sentTS": "2017-10-18T13:04:00.133Z"
            }
        ]
    },
like image 414
CarCrazyBen Avatar asked Nov 03 '17 21:11

CarCrazyBen


2 Answers

I just had the same problem, and I ended up solving it with multiple CROSS APPLY clauses.

Here's an example of my JSON:

DECLARE @PermsJSON NVARCHAR(MAX) =
N'[{
    "AppId": 1,
    "Perms":
    [{

        "Permission": ["AA", "BB"],
        "PermissionTypeID": 2
    },
    {
        "Permission": ["10"],
        "PermissionTypeID": 1
    }]
},
{
    "AppId": 2,
    "Perms":
    [{

        "Permission": ["IM", "NM"],
        "PermissionTypeID": 2
    },
    {
        "Permission": ["42"],
        "PermissionTypeID": 1
    }]
}]';

And then I can parse it using the following query:

SELECT
    a.AppId
    ,[Permission] = c.Value
    ,b.PermissionTypeID
FROM
    OPENJSON(@PermsJSON)
    WITH
        (
            AppId INT N'$.AppId'
            ,Perms NVARCHAR(MAX) AS JSON
        ) AS a
CROSS APPLY
    OPENJSON(a.Perms)
    WITH
        (
            PermissionTypeID INT
            ,[Permission] NVARCHAR(MAX) AS JSON
        ) AS b
CROSS APPLY OPENJSON(b.Permission) AS c;

The results then look like this:

AppId   Permission  PermissionTypeID
1       AA          2
1       BB          2
1       10          1
2       IM          2
2       NM          2
2       42          1
like image 91
digital.aaron Avatar answered Nov 12 '22 10:11

digital.aaron


After MUCH searching I finally discovered the answer to this issue. I simply have to include the Nested Array as another JSON column in my query, like:

WITH
 (DOC_ID                varchar(100)  '$.doc._id',
  DOC_REV               varchar(45)   '$.doc._rev',
  DELY_APPL_NAME        varchar(20)   '$.doc.delivery.application',
  DELY_SENT_BY          varchar(25)   '$.doc.delivery.sender.id',
  DELY_SENT_TYPO        varchar(20)   '$.doc.delivery.sender.type',
  RECIPS                nvarchar(max) '$.doc.delivery.recipients' as JSON,
  PAYLOAD_START_TIME    varchar(30)   '$.doc.payload.startTS',
  ....
  ...
  ..
  ) as my_query

So, I end up with one record per JSON document, with (in this case) a varchar column containing JSON text.

Next, I can run a separate query on this column to parse the JSON and create a "child table" associated with the Parent.

like image 9
CarCrazyBen Avatar answered Nov 12 '22 11:11

CarCrazyBen