#json #sql-server #tsql #sql-server-2017 #sql-server-json
#json #sql-сервер #tsql #sql-server-2017 #sql-server-json
Вопрос:
У меня есть сильно неструктурированная строка JSON, приходящая в ответ на вызов REST API:
{
"info": "Test Json Structure",
"Owner": "Self-Owned",
"managedObjects": [{
"Name": "Device1",
"Class": "A"
}, {
"Name": "Device2",
"Class_145": "Ax01",
"Class_11": "B",
"Type_125478": {
"Model": "1",
"Manufacturer": "External"
},
"Type_SD": {
"Model": "00",
"Manufacturer": "Internal"
}
}, {
"Name": "Device3",
"Class_x": "Cx11",
"Class_T": "C8Y",
"Type": {
"Model": "1x",
"Manufacturer": "Internal"
}
}
]
}
Как я могу динамически анализировать этот объект с помощью T-SQL, чтобы все дочерние элементы представляли столбцы таблицы? Что еще более важно, как обращаться с Type
, Type_125478
, Type_SD
объектами, где на самом деле они имеют одинаковую структуру ( Model, Manufacturer
), но некоторые их имена отличаются. Также имейте в виду, что устройство может отправить новый идентификатор ( Type_XYZ
), которого раньше не существовало, но, к счастью, имеет ту же структуру ( Model, Manufacturer
) .
Комментарии:
1. Таким образом, каждый раз в результате запроса у вас будет разное количество столбцов, в зависимости от того, получаете ли вы many
"Class_145"
,"Class_11"
s или нет?2. Я думаю, что лучше иметь такие типы, как type_name и type_value, вместо множества столбцов, поскольку у вас может быть только фиксированный макет результирующего набора
3. @GSerg одним из решений этого является создание полного набора столбцов, а столбцы, соответствующие json, будут иметь значения, другие будут иметь значение NULL .. это то, что R делает при разборе такой динамической строки. Вопрос в том, как сделать то же самое в T-SQL
4. @astentx это наверняка упростило бы проблему, но я не могу контролировать источник в том, как он отправляет данные
5. Какая версия SQL-Server? Поддержка JSON была введена с v2016.
Ответ №1:
Вы можете использовать что-то подобное, чтобы преобразовать все в табличную структуру и продолжить (требуется версия SQL-Server v2016 ):
DECLARE @YourJSON NVARCHAR(MAX)=
N'{
"info": "Test Json Structure",
"Owner": "Self-Owned",
"managedObjects": [{
"Name": "Device1",
"Class": "A"
}, {
"Name": "Device2",
"Class_145": "Ax01",
"Class_11": "B",
"Type_125478": {
"Model": "1",
"Manufacturer": "External"
},
"Type_SD": {
"Model": "00",
"Manufacturer": "Internal"
}
}, {
"Name": "Device3",
"Class_x": "Cx11",
"Class_T": "C8Y",
"Type": {
"Model": "1x",
"Manufacturer": "Internal"
}
}
]
}';
—запрос
SELECT A.info
,A.[Owner]
,C.[key] AS TagName
,CASE WHEN D.Model IS NULL THEN C.[value] END AS TagValue
,D.Model
,D.Manufacturer
FROM OPENJSON(@YourJSON)
WITH(info NVARCHAR(MAX)
,[Owner] NVARCHAR(MAX)
,managedObjects NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.managedObjects) B
OUTER APPLY OPENJSON(B.[value]) C
OUTER APPLY OPENJSON(CASE WHEN ISJSON(C.[value])=1 THEN C.[value] END)
WITH (Model NVARCHAR(MAX)
,Manufacturer NVARCHAR(MAX))D;
—результат
--------------------- ------------ ------------- ---------- ------- --------------
| info | Owner | TagName | TagValue | Model | Manufacturer |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Name | Device1 | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Class | A | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Name | Device2 | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Class_145 | Ax01 | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Class_11 | B | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Type_125478 | | 1 | External |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Type_SD | | 00 | Internal |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Name | Device3 | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Class_x | Cx11 | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Class_T | C8Y | | |
--------------------- ------------ ------------- ---------- ------- --------------
| Test Json Structure | Self-Owned | Type | | 1x | Internal |
--------------------- ------------ ------------- ---------- ------- --------------
Подсказка: вы можете добавить B.[key]
к результату в качестве идентификатора объекта.
Идея вкратце
- Мы используем первый
OPENJSON
, чтобы попасть в ваш JSON. ПредложениеWITH
— позволяет обращаться к JSON-реквизитам как к столбцам. Мы сами возвращаемmanagedObejcts
as JSON. - Мы используем еще один
OPENJSON
, чтобы погрузиться в управляемые объекты. - Это вернет массив объектов. Мы можем передать
value
в другойOPENJSON
. - Всякий
value
раз, когда может быть интерпретирован как JSON сам по себе, мы используем еще одинOPENJSON
, на этот раз сWITH
предложением -снова, чтобы получить внутренние реквизиты в виде столбцов.
Вы можете вставить этот результат в таблицу (объявленную, временную, физическую …) и продолжить работу с этим простым для чтения набором.
Комментарии:
1. Спасибо @Shnugo, это действительно сработало, так как я использую SQL Server 2017..