在 SQL Server 2016 中使用 JSON 进行字符串聚合
String aggregation using JSON in SQL Server 2016
我想将 json 字符串 '[{"_":7},{"_":13},{"_":17}]'
格式化为 '[7,13,17]'
在 TSQL 中尝试使用 REPLACE 方法。我必须使用 REPLACE 方法三次才能获得所需的结果。
SELECT REPLACE(REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','},{"_":',', '),'{"_":',''),'}','')
有更好的方法吗?
我正在使用 SQL Server 2016。
对此 post 进行了一些评论后,这是我的实际问题。
我有一些客户数据。客户 Table
CustomerId | Name
1 ABC
2 XYZ
3 EFG
每个客户都有一些感兴趣的领域。客户感兴趣的领域
CustomerAreaInterestId | FK_CustomerId | FK_AreaOfInterestId
1 1 2
2 1 3
3 1 5
4 2 1
5 2 2
6 3 3
7 3 4
感兴趣的区域table
AreaOfInterestId | Description
1 Interest1
2 Interest2
3 Interest3
4 Interest4
5 Interest5
在最终结果集中,我必须将感兴趣的区域 ID 作为值数组包含在内
[
{
"CustomerName": "ABC",
"AreaofInterest": "[2,3,5]"
},
{
"CustomerName": "XYZ",
"AreaofInterest": "[1,2]"
},
{
"CustomerName": "EFG",
"AreaofInterest": "[3,4]"
}
]
结果也与其他一些数据一致。为了代码简洁,我省略了。
是的,你可以只用 2 个替换来完成:
SELECT REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','{"_":',''),'}','')
除非你真的需要 space 昏迷后,这不是你老实说的。
如果您只想使用 JSON
函数(不是基于字符串的方法),下一个示例可能会有所帮助:
DECLARE @json nvarchar(max) = N'[{"_":7},{"_":13},{"_":17}]'
DECLARE @output nvarchar(max) = N'[]'
SELECT @output = JSON_MODIFY(@output, 'append $', j.item)
FROM OPENJSON(@json) WITH (item int '$."_"') j
SELECT @output AS [Result]
结果:
Result
[7,13,17]
当然,基于字符串聚合的方式也是一种可能的解决方案:
DECLARE @json nvarchar(max) = N'[{"_":7},{"_":13},{"_":17}]'
SELECT CONCAT(
N'[',
STUFF(
(
SELECT CONCAT(N',', j.item)
FROM OPENJSON(@json) WITH (item int '$."_"') j
FOR XML PATH('')
), 1, 1, N''
),
N']'
)
精简版
在尝试聚合之前将数字字段转换为文本
从评论来看,真正的问题似乎是如何在SQL Server 2016中使用JSON聚合字符串,如图in this answer。
SELECT
JSON_VALUE(
REPLACE(
(SELECT _ = someField FROM someTable FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._'
)
或者,为清楚起见重写:
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = someField
FROM someTable
FOR JSON PATH)
,'"},{"_":"',', ')
,'$[0]._')
该查询仅适用于字符串字段。在将其应用到 其他 类型之前,需要了解它的作用。
- 内部查询 从字段值生成 JSON 字符串,例如
'[{"_":"value1"},{"_":"value2"}]'
.
REPLACE
替换对象之间的引号和分隔符,将对象数组更改为 '[{"_":"value1,value2"}]'
。这是数组中的单个对象,其单个属性是逗号分隔的字符串。
JSON_VALUE(...,,'$[0]._')
提取单个数组项的 _
属性。
这个技巧不能用于数值,因为它们没有引号。解决方案是先将它们转换为文本:
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = CAST(someNumber as nvarchar(20))
FROM someTable
FOR JSON PATH)
,'"},{"_":"',', ')
,'$[0]._')
例如:
declare @t table (id int)
insert into @t
values
(7),
(13),
(17)
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = cast(ID as nvarchar(20))
FROM @t
FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._')
原始查询的唯一变化是 cast
子句。
这会产生:
7, 13, 17
此转换已本地化,因此必须注意小数点和日期,以避免产生意外结果,例如 38,5, 40,1
而不是 38.5, 40.1
。
PS: 这与 XML 技术没有什么不同,只是 STUFF
用于切断前导分隔符。该技术 也 需要将数字转换为文本,例如:
SELECT STUFF(
( SELECT N', ' + cast(ID as nvarchar(20))
FROM @t FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),
1,2,N'')
我想将 json 字符串 '[{"_":7},{"_":13},{"_":17}]'
格式化为 '[7,13,17]'
在 TSQL 中尝试使用 REPLACE 方法。我必须使用 REPLACE 方法三次才能获得所需的结果。
SELECT REPLACE(REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','},{"_":',', '),'{"_":',''),'}','')
有更好的方法吗? 我正在使用 SQL Server 2016。
对此 post 进行了一些评论后,这是我的实际问题。
我有一些客户数据。客户 Table
CustomerId | Name
1 ABC
2 XYZ
3 EFG
每个客户都有一些感兴趣的领域。客户感兴趣的领域
CustomerAreaInterestId | FK_CustomerId | FK_AreaOfInterestId
1 1 2
2 1 3
3 1 5
4 2 1
5 2 2
6 3 3
7 3 4
感兴趣的区域table
AreaOfInterestId | Description
1 Interest1
2 Interest2
3 Interest3
4 Interest4
5 Interest5
在最终结果集中,我必须将感兴趣的区域 ID 作为值数组包含在内
[
{
"CustomerName": "ABC",
"AreaofInterest": "[2,3,5]"
},
{
"CustomerName": "XYZ",
"AreaofInterest": "[1,2]"
},
{
"CustomerName": "EFG",
"AreaofInterest": "[3,4]"
}
]
结果也与其他一些数据一致。为了代码简洁,我省略了。
是的,你可以只用 2 个替换来完成:
SELECT REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','{"_":',''),'}','')
除非你真的需要 space 昏迷后,这不是你老实说的。
如果您只想使用 JSON
函数(不是基于字符串的方法),下一个示例可能会有所帮助:
DECLARE @json nvarchar(max) = N'[{"_":7},{"_":13},{"_":17}]'
DECLARE @output nvarchar(max) = N'[]'
SELECT @output = JSON_MODIFY(@output, 'append $', j.item)
FROM OPENJSON(@json) WITH (item int '$."_"') j
SELECT @output AS [Result]
结果:
Result
[7,13,17]
当然,基于字符串聚合的方式也是一种可能的解决方案:
DECLARE @json nvarchar(max) = N'[{"_":7},{"_":13},{"_":17}]'
SELECT CONCAT(
N'[',
STUFF(
(
SELECT CONCAT(N',', j.item)
FROM OPENJSON(@json) WITH (item int '$."_"') j
FOR XML PATH('')
), 1, 1, N''
),
N']'
)
精简版
在尝试聚合之前将数字字段转换为文本
从评论来看,真正的问题似乎是如何在SQL Server 2016中使用JSON聚合字符串,如图in this answer。
SELECT
JSON_VALUE(
REPLACE(
(SELECT _ = someField FROM someTable FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._'
)
或者,为清楚起见重写:
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = someField
FROM someTable
FOR JSON PATH)
,'"},{"_":"',', ')
,'$[0]._')
该查询仅适用于字符串字段。在将其应用到 其他 类型之前,需要了解它的作用。
- 内部查询 从字段值生成 JSON 字符串,例如
'[{"_":"value1"},{"_":"value2"}]'
. REPLACE
替换对象之间的引号和分隔符,将对象数组更改为'[{"_":"value1,value2"}]'
。这是数组中的单个对象,其单个属性是逗号分隔的字符串。JSON_VALUE(...,,'$[0]._')
提取单个数组项的_
属性。
这个技巧不能用于数值,因为它们没有引号。解决方案是先将它们转换为文本:
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = CAST(someNumber as nvarchar(20))
FROM someTable
FOR JSON PATH)
,'"},{"_":"',', ')
,'$[0]._')
例如:
declare @t table (id int)
insert into @t
values
(7),
(13),
(17)
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = cast(ID as nvarchar(20))
FROM @t
FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._')
原始查询的唯一变化是 cast
子句。
这会产生:
7, 13, 17
此转换已本地化,因此必须注意小数点和日期,以避免产生意外结果,例如 38,5, 40,1
而不是 38.5, 40.1
。
PS: 这与 XML 技术没有什么不同,只是 STUFF
用于切断前导分隔符。该技术 也 需要将数字转换为文本,例如:
SELECT STUFF(
( SELECT N', ' + cast(ID as nvarchar(20))
FROM @t FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),
1,2,N'')