SQL 到 JSON - SQL 2016 中的对象数组到值数组
SQL to JSON - array of objects to array of values in SQL 2016
SQL 2016 有一项新功能,可以将 SQL 服务器上的数据转换为 JSON。我很难将对象数组组合成值数组,即
示例 -
CREATE TABLE #temp (item_id VARCHAR(256))
INSERT INTO #temp VALUES ('1234'),('5678'),('7890')
SELECT * FROM #temp
--convert to JSON
SELECT (SELECT item_id
FROM #temp
FOR JSON PATH,root('ids'))
结果 -
{
"ids": [{
"item_id": "1234"
},
{
"item_id": "5678"
},
{
"item_id": "7890"
}]
}
但我想要的结果是 -
"ids": [
"1234",
"5678",
"7890"
]
有人可以帮我吗?
谢谢!我们发现的灵魂首先转化为 XML -
SELECT
JSON_QUERY('[' + STUFF(( SELECT ',' + '"' + item_id + '"'
FROM #temp FOR XML PATH('')),1,1,'') + ']' ) ids
FOR JSON PATH , WITHOUT_ARRAY_WRAPPER
马丁!
我相信这是一种更简单的方法:
SELECT '"ids": ' +
REPLACE(
REPLACE( (SELECT item_id FROM #temp FOR JSON AUTO),'{"item_id":','' ),
'"}','"' )
由于原始值数组是有效的 JSON,SQL 服务器的 JSON 功能中没有内置用于选择原始值数组的工具,这似乎很奇怪。 (如果相反存在这样的功能,我至少在搜索了很多之后还没有发现它)。
上述方法的工作原理与描述的一样。但是当在更大的查询中申请一个字段时,原语数组被引号包围。
例如,这个
DECLARE @BomTable TABLE (ChildNumber dbo.udt_ConMetPartNumber);
INSERT INTO @BomTable (ChildNumber) VALUES (N'101026'), (N'101027');
SELECT N'"Children": ' + REPLACE(REPLACE((SELECT ChildNumber FROM @BomTable FOR JSON PATH), N'{"ChildNumber":', N''), '"}','');
通过制作作品:
"Children": ["101026,"101027]
但是,按照上面的方法,这:
SELECT
p.PartNumber,
p.Description,
REPLACE(REPLACE((SELECT
ChildNumber
FROM
Part.BillOfMaterials
WHERE
ParentNumber = p.PartNumber
ORDER BY
ChildNumber
FOR
JSON AUTO
), N'{"ChildNumber":', N''), '"}', '"') AS [Children]
FROM
Part.Parts AS p
WHERE
p.PartNumber = N'104444'
FOR
JSON PATH
生产:
[
{
"PartNumber": "104444",
"Description": "ASSY HUB R-SER DRIV HP10 ABS",
"Children": "[\"101026\",\"101027\",\"102291\",\"103430\",\"103705\",\"104103\"]"
}
]
其中 Children 数组被包装为字符串。
大多数这些解决方案本质上都是创建一个表示数组内容的 CSV,然后将该 CSV 放入最终的 JSON 格式。这是我使用的,以避免 XML:
DECLARE @tmp NVARCHAR(MAX) = ''
SELECT @tmp = @tmp + '"' + [item_id] + '",'
FROM #temp -- Defined and populated in the original question
SELECT [ids] = JSON_QUERY((
SELECT CASE
WHEN @tmp IS NULL THEN '[]'
ELSE '[' + SUBSTRING(@tmp, 0, LEN(@tmp)) + ']'
END
))
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
declare @temp table (item_id VARCHAR(256))
INSERT INTO @temp VALUES ('1234'),('5678'),('7890')
SELECT * FROM @temp
--convert to JSON
select
json_query(QUOTENAME(STRING_AGG('"' + STRING_ESCAPE(item_id, 'json') + '"', char(44)))) as [json]
from @temp
for json path
当我们想将字符串连接成 json 数组时:
转义字符串 - STRING_ESCAPE
用逗号分隔符连接字符串 - STRING_AGG,逗号ascii码为44
在括号中添加引号 - QUOTENAME(不带参数)
return 字符串(包含元素数组)为 json - JSON_QUERY
此版本(基于其他版本):
- 正确转义特殊 JSON 个字符(例如引号)
- returns空数组
[]
没有数据
需要 SQL 2017 年或以后(由于 STRING_AGG
):
SELECT
CONCAT('[',
(SELECT STRING_AGG('"' + STRING_ESCAPE(item_id, 'json') + '"', ',')
FROM #temp)
, ']')
这是一个可能可行也可能不可行的疯狂想法。递归遍历您的数据集并使用 JSON_MODIFY
:
将内容附加到您的 JSON 数组
with
d (d) as (select * from (values (1),(2),(3),(4)) t (d)),
j (d, j) as (
-- Adapt the recursion to make it dynamic
select 1, json_modify('[]', 'append $', d)
from d
where d = 1
union all
select d.d, json_modify(j, 'append $', d.d)
from d join j on d.d = j.d + 1
)
select *
from j;
出于说明目的,我保持简单。当然,您将对其进行调整以使其动态化。这会产生:
|d |j |
|---|---------|
|1 |[1] |
|2 |[1,2] |
|3 |[1,2,3] |
|4 |[1,2,3,4]|
甚至可以用来模拟标准 SQL JSON_ARRAYAGG
SQL 2016 有一项新功能,可以将 SQL 服务器上的数据转换为 JSON。我很难将对象数组组合成值数组,即
示例 -
CREATE TABLE #temp (item_id VARCHAR(256))
INSERT INTO #temp VALUES ('1234'),('5678'),('7890')
SELECT * FROM #temp
--convert to JSON
SELECT (SELECT item_id
FROM #temp
FOR JSON PATH,root('ids'))
结果 -
{
"ids": [{
"item_id": "1234"
},
{
"item_id": "5678"
},
{
"item_id": "7890"
}]
}
但我想要的结果是 -
"ids": [
"1234",
"5678",
"7890"
]
有人可以帮我吗?
谢谢!我们发现的灵魂首先转化为 XML -
SELECT
JSON_QUERY('[' + STUFF(( SELECT ',' + '"' + item_id + '"'
FROM #temp FOR XML PATH('')),1,1,'') + ']' ) ids
FOR JSON PATH , WITHOUT_ARRAY_WRAPPER
马丁!
我相信这是一种更简单的方法:
SELECT '"ids": ' +
REPLACE(
REPLACE( (SELECT item_id FROM #temp FOR JSON AUTO),'{"item_id":','' ),
'"}','"' )
由于原始值数组是有效的 JSON,SQL 服务器的 JSON 功能中没有内置用于选择原始值数组的工具,这似乎很奇怪。 (如果相反存在这样的功能,我至少在搜索了很多之后还没有发现它)。
上述方法的工作原理与描述的一样。但是当在更大的查询中申请一个字段时,原语数组被引号包围。
例如,这个
DECLARE @BomTable TABLE (ChildNumber dbo.udt_ConMetPartNumber);
INSERT INTO @BomTable (ChildNumber) VALUES (N'101026'), (N'101027');
SELECT N'"Children": ' + REPLACE(REPLACE((SELECT ChildNumber FROM @BomTable FOR JSON PATH), N'{"ChildNumber":', N''), '"}','');
通过制作作品:
"Children": ["101026,"101027]
但是,按照上面的方法,这:
SELECT
p.PartNumber,
p.Description,
REPLACE(REPLACE((SELECT
ChildNumber
FROM
Part.BillOfMaterials
WHERE
ParentNumber = p.PartNumber
ORDER BY
ChildNumber
FOR
JSON AUTO
), N'{"ChildNumber":', N''), '"}', '"') AS [Children]
FROM
Part.Parts AS p
WHERE
p.PartNumber = N'104444'
FOR
JSON PATH
生产:
[
{
"PartNumber": "104444",
"Description": "ASSY HUB R-SER DRIV HP10 ABS",
"Children": "[\"101026\",\"101027\",\"102291\",\"103430\",\"103705\",\"104103\"]"
}
]
其中 Children 数组被包装为字符串。
大多数这些解决方案本质上都是创建一个表示数组内容的 CSV,然后将该 CSV 放入最终的 JSON 格式。这是我使用的,以避免 XML:
DECLARE @tmp NVARCHAR(MAX) = ''
SELECT @tmp = @tmp + '"' + [item_id] + '",'
FROM #temp -- Defined and populated in the original question
SELECT [ids] = JSON_QUERY((
SELECT CASE
WHEN @tmp IS NULL THEN '[]'
ELSE '[' + SUBSTRING(@tmp, 0, LEN(@tmp)) + ']'
END
))
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
declare @temp table (item_id VARCHAR(256))
INSERT INTO @temp VALUES ('1234'),('5678'),('7890')
SELECT * FROM @temp
--convert to JSON
select
json_query(QUOTENAME(STRING_AGG('"' + STRING_ESCAPE(item_id, 'json') + '"', char(44)))) as [json]
from @temp
for json path
当我们想将字符串连接成 json 数组时:
转义字符串 - STRING_ESCAPE
用逗号分隔符连接字符串 - STRING_AGG,逗号ascii码为44
在括号中添加引号 - QUOTENAME(不带参数)
return 字符串(包含元素数组)为 json - JSON_QUERY
此版本(基于其他版本):
- 正确转义特殊 JSON 个字符(例如引号)
- returns空数组
[]
没有数据
需要 SQL 2017 年或以后(由于 STRING_AGG
):
SELECT
CONCAT('[',
(SELECT STRING_AGG('"' + STRING_ESCAPE(item_id, 'json') + '"', ',')
FROM #temp)
, ']')
这是一个可能可行也可能不可行的疯狂想法。递归遍历您的数据集并使用 JSON_MODIFY
:
with
d (d) as (select * from (values (1),(2),(3),(4)) t (d)),
j (d, j) as (
-- Adapt the recursion to make it dynamic
select 1, json_modify('[]', 'append $', d)
from d
where d = 1
union all
select d.d, json_modify(j, 'append $', d.d)
from d join j on d.d = j.d + 1
)
select *
from j;
出于说明目的,我保持简单。当然,您将对其进行调整以使其动态化。这会产生:
|d |j |
|---|---------|
|1 |[1] |
|2 |[1,2] |
|3 |[1,2,3] |
|4 |[1,2,3,4]|
甚至可以用来模拟标准 SQL JSON_ARRAYAGG