Выбранный ответ действительно отвечает на тот вопрос, который я изначально задавал, поэтому он все еще правильный. Но вот что я нашел, используя это. Во-первых, если у вас есть числовые значения, вам нужно будет включать кавычки с обеих сторон в выражении concat. Во-вторых, чтобы это работало, мне пришлось включить параметр lax
в JSON_MODIFY
, чтобы он игнорировал несуществующие пути. И это сценарий, который я использовал для преобразования столбца с тремя значениями во вложенные объекты:
DECLARE @json nvarchar(max) = N'{}'
;WITH ParsedCTE AS (
SELECT
CASE WHEN CHARINDEX('.', ID) = 0
THEN ID
ELSE LEFT(ID, CHARINDEX('.', ID) - 1)
END
AS a
FROM [SERVER].[DATABASE].[SCHEMA].[TABLE]
)
SELECT @json = JSON_MODIFY(@json, CONCAT('lax $."', a, '"'), JSON_QUERY(N'{}'))
FROM ParsedCTE
;WITH ParsedCTE AS (
SELECT
CASE WHEN CHARINDEX('.', ID) = 0
THEN ID
ELSE LEFT(ID, CHARINDEX('.', ID) - 1)
END
AS a,
CASE WHEN CHARINDEX('.', ID) = 0
THEN null
WHEN CHARINDEX('.', ID, CHARINDEX('.', ID) + 1) = 0
THEN RIGHT(ID, LEN(ID) - CHARINDEX('.', ID))
ELSE SUBSTRING(ID, CHARINDEX('.', ID) + 1, LEN(ID) - CHARINDEX('.', ID, CHARINDEX('.', ID) + 1))
END
AS b
FROM [SERVER].[DATABASE].[SCHEMA].[TABLE]
WHERE
CASE WHEN CHARINDEX('.', ID) = 0
THEN null
WHEN CHARINDEX('.', ID, CHARINDEX('.', ID) + 1) = 0
THEN RIGHT(ID, LEN(ID) - CHARINDEX('.', ID))
ELSE SUBSTRING(ID, CHARINDEX('.', ID) + 1, LEN(ID) - CHARINDEX('.', ID, CHARINDEX('.', ID) + 1))
END IS NOT NULL
)
SELECT @json = JSON_MODIFY(@json, CONCAT('lax $."', a, '"."', b, '"'), JSON_QUERY(N'{}'))
FROM ParsedCTE
;WITH ParsedCTE AS (
SELECT
CASE WHEN CHARINDEX('.', ID) = 0
THEN ID
ELSE LEFT(ID, CHARINDEX('.', ID) - 1)
END
AS a,
CASE WHEN CHARINDEX('.', ID) = 0
THEN null
WHEN CHARINDEX('.', ID, CHARINDEX('.', ID) + 1) = 0
THEN RIGHT(ID, LEN(ID) - CHARINDEX('.', ID))
ELSE SUBSTRING(ID, CHARINDEX('.', ID) + 1, LEN(ID) - CHARINDEX('.', ID, CHARINDEX('.', ID) + 1))
END
AS b,
CASE WHEN CHARINDEX('.', ID) = 0
THEN null
WHEN CHARINDEX('.', ID, CHARINDEX('.', ID) + 1) = 0
THEN null
ELSE RIGHT(ID, LEN(ID) - CHARINDEX('.', ID, CHARINDEX('.', ID) + 1))
END
AS c
FROM [SERVER].[DATABASE].[SCHEMA].[TABLE]
WHERE
CASE WHEN CHARINDEX('.', ID) = 0
THEN null
WHEN CHARINDEX('.', ID, CHARINDEX('.', ID) + 1) = 0
THEN null
ELSE RIGHT(ID, LEN(ID) - CHARINDEX('.', ID, CHARINDEX('.', ID) + 1))
END IS NOT NULL
)
SELECT @json = JSON_MODIFY(@json, CONCAT('lax $."', a, '"."', b, '"."', c, '"'), 'true')
FROM ParsedCTE
SELECT JSON_QUERY(@json) AS ID
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
Я пытался сделать все это в одном рекурсивном выражении CTE, но это всегда перезаписывает объекты, так какэто не создало экземпляры родителей как способных к путям объектов. Поэтому, чтобы достичь этого, мне пришлось заново модифицировать JSON для каждого уровня, который я хотел определить.
К сожалению, это привело к времени выполнения ~ 4s . Так что это определенно не подходит для данных в реальном времени, сейчас я думаю о реализации кэша на моем внутреннем сервере, чтобы уменьшить это влияние.
Другое обновление
Я пошел дальше и вернулся к чему-то более похожему на сценарий исходного ответа, поскольку у него более короткое (но все же немаловажное) время выполнения, и я понял, что оно не стоит всех усилий, когда у меня только ограниченное числопредметов, которые имеют три значения. Я просто собираюсь, чтобы второе и третье поля всегда были одной строкой. Но я надеюсь, что кто-то может извлечь выгоду из сценария.