在 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}]','{"_":',''),'}','')

DEMO HERE

除非你真的需要 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'')