I've got the following JSON.
[
{
"attributes": {
"2003": "Some text",
"2004": 0,
"2006": 0,
"2008": 0,
"2011": 0,
"2120": 0
},
"path": "/Path1",
"changeDate": "2019-11-11T13:56:37.987Z",
"guid": "00000000-0000-0000-0000-000000000000",
"version": 0,
"timestamp": "2019-11-11T14:21:14.86427Z"
},
{
"attributes": {
"2121": 0,
"2297": 0,
"2298": 0,
"2299": 0,
"2805": 0,
"8501": 0,
"12004": 0,
"13266": 0,
"13282": 0
},
"path": "P:/Path2/SubPath",
"changeDate": "2019-11-11T13:55:35.943Z",
"guid": "705b30ab-53b0-42ee-bb98-6d80daae2e18",
"version": 1,
"timestamp": "2019-11-11T09:08:54.417Z"
},
{
"attributes": {},
"path": "PP:/OneMorePath",
"changeDate": "2019-11-11T14:20:49.5Z",
"guid": "b9aac8f3-1f2a-4b52-b8d8-af6b654d3f0f",
"version": 41,
"timestamp": "2019-11-11T13:26:24.723Z"
}
]
For this I have two SQL Server tables.
CREATE TABLE [dbo].[Foo]
(
[Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT(NEWID()),
[Path] NVARCHAR(128) NOT NULL,
[ChangeDate] DATETIME NOT NULL,
[Guid] UNIQUEIDENTIFIER NOT NULL,
[Version] INT NOT NULL,
[Timestamp] DATETIME NOT NULL
)
CREATE TABLE [dbo].[FooAttributes]
(
[Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT(NEWID()),
[IdFoo] UNIQUEIDENTIFIER NOT NULL,
[Key] INT NOT NULL,
[Value] NVARCHAR(255) NOT NULL
)
For the header data I can query it in SQL Server.
SELECT *
FROM OPENJSON(@Json)
WITH (
[Path] NVARCHAR(128) 'strict $.path',
[ChangeDate] DATETIME2 '$.changeDate',
[Guid] UNIQUEIDENTIFIER '$.guid',
[Version] INT '$.version',
[Timestamp] DATETIME2 '$.timestamp'
)
And for this I get this result.
Path | ChangeDate | Guid | Version | Timestamp
------------------------------------------------------------------------------------------------------------------------------------------------
/Path1 | 2019-11-11 13:56:37.9870000 | 00000000-0000-0000-0000-000000000000 | 0 | 2019-11-11 14:21:14.8642700
P:/Path2/SubPath | 2019-11-11 13:55:35.9430000 | 705B30AB-53B0-42EE-BB98-6D80DAAE2E18 | 1 | 2019-11-11 09:08:54.4170000
PP:/OneMorePath | 2019-11-11 14:20:49.5000000 | B9AAC8F3-1F2A-4B52-B8D8-AF6B654D3F0F | 41 | 2019-11-11 13:26:24.7230000
This is ok. But I can't find any possibility to query the attributes to get this in the kind shown below because this is not an array of key/value pairs but fields with values.
IdFoo | AttributeName | AttributeValue
---------------------------------------
<IdFoo1> | 2003 | Some text
<IdFoo1> | 2004 | 0
<IdFoo1> | 2006 | 0
<IdFoo1> | 2008 | 0
<IdFoo1> | 2011 | 0
<IdFoo1> | 2120 | 0
<IdFoo2> | 2121 | 0
<IdFoo2> | 2297 | 0
<IdFoo2> | 2298 | 0
<IdFoo2> | 2299 | 0
<IdFoo2> | 2805 | 0
<IdFoo2> | 8501 | 0
<IdFoo2> | 12004 | 0
<IdFoo2> | 13266 | 0
<IdFoo2> | 13282 | 0
Is there something possible in SQL Server 2016 to get this substructure as wanted?
You need to parse the input JSON array with explicit schema using AS JSON to specify that the $attributes property contains an inner JSON object. After that you need to use additional CROSS APPLY operator with another OPENJSON() call with default schema (without the WITH clause), that returns a table with key, value and type columns.
JSON:
DECLARE @json nvarchar(max) = N'[
{
"attributes": {
"2003": "Some text",
"2004": 0,
"2006": 0,
"2008": 0,
"2011": 0,
"2120": 0
},
"path": "/Path1",
"changeDate": "2019-11-11T13:56:37.987Z",
"guid": "00000000-0000-0000-0000-000000000000",
"version": 0,
"timestamp": "2019-11-11T14:21:14.86427Z"
},
{
"attributes": {
"2121": 0,
"2297": 0,
"2298": 0,
"2299": 0,
"2805": 0,
"8501": 0,
"12004": 0,
"13266": 0,
"13282": 0
},
"path": "P:/Path2/SubPath",
"changeDate": "2019-11-11T13:55:35.943Z",
"guid": "705b30ab-53b0-42ee-bb98-6d80daae2e18",
"version": 1,
"timestamp": "2019-11-11T09:08:54.417Z"
},
{
"attributes": {},
"path": "PP:/OneMorePath",
"changeDate": "2019-11-11T14:20:49.5Z",
"guid": "b9aac8f3-1f2a-4b52-b8d8-af6b654d3f0f",
"version": 41,
"timestamp": "2019-11-11T13:26:24.723Z"
}
]'
Statement:
SELECT
j1.Guid,
j2.[key] AS AttrName,
j2.[value] AS AttrValue
FROM OPENJSON(@json, '$') WITH (
Guid UNIQUEIDENTIFIER '$.guid',
-- other columns definitions
attributes nvarchar(max) '$.attributes' AS JSON
) j1
CROSS APPLY OPENJSON(j1.attributes) j2
Results:
Guid AttrName AttrValue
00000000-0000-0000-0000-000000000000 2003 Some text
00000000-0000-0000-0000-000000000000 2004 0
00000000-0000-0000-0000-000000000000 2006 0
00000000-0000-0000-0000-000000000000 2008 0
00000000-0000-0000-0000-000000000000 2011 0
00000000-0000-0000-0000-000000000000 2120 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 2121 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 2297 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 2298 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 2299 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 2805 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 8501 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 12004 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 13266 0
705b30ab-53b0-42ee-bb98-6d80daae2e18 13282 0
Using As Json with Cross apply and another OpenJson can give you the desired results:
SELECT [Guid], [key], [value]
FROM OPENJSON(@Json)
WITH (
[Guid] UNIQUEIDENTIFIER '$.guid',
[Attributes] NVARCHAR(max) '$.attributes' As Json
)
CROSS APPLY OPENJSON(Attributes)
Note that the key is nvarchar(4000) and value is nvarchar(max).
See a live demo on DbFiddle<>UK
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With