I have a JSON column that has about 300k worth of properties, and I want to attempt to export it in such a way that I can get the full path and value of the property. Note, my JSON has no arrays - it's basically a JSON for a web application translations.
To provide a simple example with the following JSON I want to get back the following:
JSON:
{"Name":"Jeff", "Address": {"Street": "123 Harrow Street", "City": "Dublin"}}
Expected Output:
|----------------|-------------------|
| path | value |
|----------------|-------------------|
| Name | Jeff |
| Address.Street | 123 Harrow Street |
| Address.City | Dublin |
|----------------|-------------------|
Or if it's easier I can do with the $.
because I'd like to be able to easily update the values for each property - with JSON_MODIFY
.
I've tried using OPENJSON but that only appears to return 3 fields key, value and type, but at least the key here doesn't go past the field level of values, so I get: Query:
DECLARE @json_doc nvarchar(4000) = '{"Name":"Jeff", "Address": {"Street": "123 Harrow Street", "City": "Dublin"}}';
SELECT [key], [value]
FROM OPENJSON(@json_doc);
GO
Output:
|---------|---------------------------------------------------|
| key | value |
|---------|---------------------------------------------------|
| Name | Jeff |
| Address | {"Street": "123 Harrow Street", "City": "Dublin"} |
|---------|---------------------------------------------------|
Is there a way to get the OPENJSON query to be fully recursive? Or is there another way? I've tried googling but it doesn't appear to be a common request?
A recursive CTE is an option. You need to use ISJSON()
as a termination condition in the recursive member of the query:
DECLARE @json_doc nvarchar(4000) = '{"Name":"Jeff", "Address": {"Street": "123 Harrow Street", "City": "Dublin"}}';
;WITH rCTE AS (
SELECT
CONVERT(nvarchar(max), N'$') COLLATE DATABASE_DEFAULT AS [path],
CONVERT(nvarchar(max), JSON_QUERY(@json_doc, '$')) COLLATE DATABASE_DEFAULT AS [value]
UNION ALL
SELECT
CONVERT(nvarchar(max), CONCAT(r.path, CONCAT(N'.', c.[key]))) COLLATE DATABASE_DEFAULT ,
CONVERT(nvarchar(max), c.[value]) COLLATE DATABASE_DEFAULT
FROM rCTE r
CROSS APPLY OPENJSON(r.[value]) c
WHERE ISJSON(r.[value]) = 1
)
SELECT *
FROM rCTE
WHERE ISJSON([value]) = 0
Result:
path value
----------------------------------
$.Name Jeff
$.Address.Street 123 Harrow Street
$.Address.City Dublin