我有一个包含 3 列的表,我想查询该表,结果将是一个 JSON 对象。
示例数据如下所示:
CREATE TABLE #Test (ValueV INT, KEYS NVARCHAR (100), ID INT)
INSERT INTO #Test
VALUES (1, N'ChangeAdress 19 - 21', 200),
(1, N'ChangeAdress 20 - 22', 200),
(1, N'ChangeAdress 22 - 24', 300),
(1, N'ChangeAdress 23 - 25', 300),
(2, N'ChangeAdress 24 - 26', 400),
(2, N'ChangeAdress 25 - 27', 400),
(3, N'ChangeAdress 26 - 28', 400),
(3, N'ChangeAdress 27 - 29', 400)
SELECT * FROM #Test
我的查询尝试:
SELECT ID, Keys, ValueV
FROM #Test
GROUP BY ID, keys, ValueV
FOR JSON AUTO
但这会返回 1 个 JSON“行”。我想要的是每组一行。这里的Group就是ID,Value的组合。我对 JSON 对象缺乏经验(这可能从此查询中可见),因此我们将不胜感激。
所需的输出(但随后为每行 JSON):
--------------------------------------------------
|200, 1, ChangeAdress 19 - 21, ChangeAdress 20 - 22|
|300, 1, ChangeAdress 22 - 24, ChangeAdress 23 - 25|
|400, 2, ChangeAdress 24 - 26, ChangeAdress 25 - 27|
|400, 3, ChangeAdress 26 - 28, ChangeAdress 27 - 29|
提前致谢!
这可行(在 SQL Server 2017 中,
STRING_AGG
可用),但相当笨拙。我不确定还有没有更优雅的方法。
SELECT (
SELECT
ID,
ValueV,
Keys = JSON_QUERY('["' + STRING_AGG(STRING_ESCAPE(Keys, 'json'), '","') + '"]')
FOR JSON PATH
)
FROM #Test
GROUP BY ID, ValueV
对于 SQL Server 2016(没有
STRING_AGG
或 STRING_ESCAPE
):
SELECT (
SELECT ID, ValueV, Keys = JSON_QUERY(REPLACE(REPLACE(
(
SELECT Keys
FROM #Test t2 WHERE t2.ID = t1.ID AND t2.ValueV = t1.ValueV
FOR JSON PATH
),
'{"Keys":', ''),
'}', ''))
FOR JSON PATH
)
FROM #Test t1
GROUP BY ID, ValueV
更不优雅,但你能得到什么就拿什么。至少我们没有连接
FOR XML
...
如果有人有相同的用例,请发布此内容
SELECT [t].[ID],
(SELECT [t1].[KEYS], [t1].[ValueV] FROM @Test t1 WHERE t1.[ID] = [t].id FOR JSON PATH ) a
FROM @Test AS [t]
GROUP BY [t].[ID]
我的两分钱:
有趣的是,您需要有效的单独 JSON 行,而不是单个 JSON 字符串。无论如何,这里有一些替代答案,尽管接受的答案是最好的答案。
-- 100% hardcoded yourself. Pre SQL Server 2016
SELECT '[{"ID":' + convert(nvarchar(4),T1.[ID]) + ',"ValueV":' + convert(nvarchar(4),T1.[ValueV]) + ',"Keys":["' + T1.[Keys] + '","' + T2.[Keys] + '"]}]' AS [keys]
FROM #Test AS T1 INNER JOIN #Test T2 ON t2.ID = t1.ID AND t2.ValueV = t1.ValueV AND t2.keys > t1.keys
或者:
-- Use the OPENJSON to output your results as a dataset and not just a single row. I've removed the escape character back slashes to match the accepted answers output
SELECT
'[' + REPLACE((REPLACE((REPLACE([value], '\','')),':"[',':[')),']"}',']}') + ']'
FROM OPENJSON(
(SELECT T1.[ID],T1.[ValueV], '["' + T1.[Keys] + '","' + T2.[Keys] + '"]' AS [keys]
FROM #Test AS T1 INNER JOIN #Test T2 ON t2.ID = t1.ID AND t2.ValueV = t1.ValueV AND t2.keys > t1.keys
FOR JSON PATH))
或者:
-- This is a lot cleaner for an array of values in pairs. Again using OPENJSON to output your desired result.
select
'[' + [Value] + ']' FROM OPENJSON(
(select T1.[ID], T1.[ValueV], JSON_MODIFY(JSON_MODIFY('[]','append lax $',t0.keys),'append lax $',t1.keys) as keys
FROM #Test AS T0 inner join #Test as t1
on t0.ID = t1.ID AND t0.ValueV = t1.ValueV AND t0.keys < t1.keys
FOR JSON path))
请注意,JSON 本身不是一个对象,而只是一串命名值对,有效的 JavaScript,但仍然是一个子集,当您想要一个嵌套的 Javascript 对象时,它看起来完全不同(如果 JS 是您想要的数据目的地) ,我在这里假设)。 JSON 函数非常适合快速提取数据以进行传输,但是当您需要嵌套输出或针对值数组而不是对象对数据集进行分组时,它可能会变得相当棘手。就我个人而言,因为它是一个字符串,所以对于更复杂的东西我只是自己构建它。希望这是一个不同的看法。
试试这个:
SELECT (SELECT [ID], [Keys], [ValueV] FOR JSON PATH)
FROM #Test
GROUP BY ID, keys, ValueV
或者这个:
SELECT (SELECT [ID], [Keys], [ValueV] FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)
FROM #Test
GROUP BY ID, keys, ValueV
你可能会这样做:
SELECT
(SELECT ID, ValueV, KEYS
FROM Test Test2
WHERE (Test2.ValueV = Test.ValueV AND Test2.ID = Test.ID) FOR JSON PATH) JSON
FROM Test
GROUP BY ValueV, ID
或者将分组列保留在 JSON 列之外:
SELECT
ID, ValueV,
(SELECT KEYS
FROM Test Test2
WHERE (Test2.ValueV = Test.ValueV AND Test2.ID = Test.ID) FOR JSON PATH) JSON
FROM Test
GROUP BY ValueV, ID
这就是我们想要的吗?
with test as
( select 1 ValueV , N'ChangeAdress 19 - 21' KEYS , 200 id
union all
select 1, N'ChangeAdress 20 - 22', 200
union all
select 1, N'ChangeAdress 22 - 24', 300
union all
select 1, N'ChangeAdress 23 - 25', 300
union all
select 2, N'ChangeAdress 24 - 26', 400
union all
select 2, N'ChangeAdress 25 - 27', 400
union all
select 3, N'ChangeAdress 26 - 28', 400
union all
select 3, N'ChangeAdress 27 - 29', 400
)
select c.ValueV,id,(select * from test
where ValueV = c.ValueV and id = c.id
for json path
)x
from test c
group by c.ValueV,c.id**