К сожалению, разработчики забыли добавить что-то вроде AS ARRAY
подсказка.
OPENJSON()
может прочитать голый массив , где [key]
- это позиция элемента, а [value]
это элемент, но мы не можем создать такой массив с функциональностью JSON:
Есть несколько обходных путей:
- Создайте макет для имитации вашей проблемы:
DECLARE @tbl1 TABLE(ID INT IDENTITY,SomeValue VARCHAR(100));
INSERT INTO @tbl1 VALUES('Row 1'),('Row 2');
DECLARE @tbl2 TABLE(ID1 INT,SomeDetail VARCHAR(100));
INSERT INTO @tbl2 VALUES(1,'Det 1.1'),(1,'Det 1.2')
,(2,'Det 2.1'),(2,'Det 2.2.'),(2,'Det 2.3');
- Использование режима AUTO
обнаружит JOIN
и создаст массив объектов.
- Это близко, но вы не получите безымянный массив:
SELECT *
FROM @tbl1 t1
INNER JOIN @tbl2 t2 ON t1.ID=t2.ID1
FOR JSON AUTO;
/*
{
"ID": 1,
"SomeValue": "Row 1",
"t2": [
{
"ID1": 1,
"SomeDetail": "Det 1.1"
},
{
"ID1": 1,
"SomeDetail": "Det 1.2"
}
]
}
*/
- Использование режима PATH
вернет каждую комбинацию - не то, что вам нужно
SELECT *
FROM @tbl1 t1
INNER JOIN @tbl2 t2 ON t1.ID=t2.ID1
FOR JSON PATH;
/*
{
"ID": 1,
"SomeValue": "Row 1",
"ID1": 1,
"SomeDetail": "Det 1.1"
}
*/
- Использование коррелированного подзапроса приведет к тому жерезультат в режиме AUTO
выше
SELECT *
,(
SELECT *
FROM @tbl2 t2
WHERE t2.ID1=t1.ID --<-- correlated sub-query
FOR JSON PATH
) AS Details
FROM @tbl1 t1
FOR JSON PATH;
- Таким образом, мы можем использовать коррелированный подзапрос вместе с XML-хаком для конкатенации строк:
SELECT *
,JSON_QUERY
(
CONCAT('['
,STUFF((
SELECT CONCAT(',"',t2.SomeDetail,'"')
FROM @tbl2 t2
WHERE t2.ID1=t1.ID --<-- correlated sub-query
FOR XML PATH(''),TYPE).value('.','nvarchar(max)'),1,1,''),']')
) AS Details
FROM @tbl1 t1
FOR JSON PATH;
- Наконец, это то, что вы хотите:
/*
{
"ID": 1,
"SomeValue": "Row 1",
"Details": [
"Det 1.1",
"Det 1.2"
]
}
*/
Если у вас v2017 +, вам повезло, потому что вы можете использовать STRING_AGG()
:
SELECT t1.ID
,JSON_QUERY(CONCAT('[',STRING_AGG(CONCAT('"',t2.SomeDetail,'"'),','),']')) AS Details
FROM @tbl1 t1
INNER JOIN @tbl2 t2 ON t1.ID=t2.ID1
GROUP BY t1.ID
FOR JSON PATH;
На данный момент нам нужно дождаться будущей версии, которая принесет эту действительно необходимую функцию изначально ...