简体   繁体   English

在 SQL Server 2016 中使用 JSON 进行字符串聚合

[英]String aggregation using JSON in SQL Server 2016

I would like to format a json string '[{"_":7},{"_":13},{"_":17}]' as '[7,13,17]' Tried with REPLACE Method in TSQL.我想将 json 字符串'[{"_":7},{"_":13},{"_":17}]' '[7,13,17]''[7,13,17]' TSQL。 I have to use REPLACE method three times to get the desire result.我必须使用 REPLACE 方法三次才能得到想要的结果。

SELECT REPLACE(REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','},{"_":',', '),'{"_":',''),'}','')

is there a better way to do that?有没有更好的方法来做到这一点? I am using SQL Server 2016.我正在使用 SQL Server 2016。

After some comments for this post, This my actual issue.在对这篇文章发表一些评论之后,这是我的实际问题。

I have some customer data.我有一些客户数据。 Customer Table客户表

CustomerId | Name
    1         ABC
    2         XYZ
    3         EFG

each customer has some area of interest.每个客户都有一些感兴趣的领域。 Customer Area of Interest客户感兴趣的领域

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

Area of interest table兴趣区表

   AreaOfInterestId | Description
       1                Interest1
       2                Interest2
       3                Interest3
       4                Interest4
       5                Interest5

In the final result set, I have to include area of interest id's as an array of value在最终结果集中,我必须将感兴趣的区域 id 作为值数组包含在内

[
{
    "CustomerName": "ABC",
    "AreaofInterest": "[2,3,5]"
},
{
    "CustomerName": "XYZ",
    "AreaofInterest": "[1,2]"
},
{
    "CustomerName": "EFG",
    "AreaofInterest": "[3,4]"
}
]

The result consists with some other data's as well.结果还包含一些其他数据。 I have omitted for the code brevity.为了代码简洁,我省略了。

Short Version精简版

Cast the numeric field to text before trying to aggregate it在尝试聚合之前将数字字段转换为文本


From the comments, it looks like the real question is how to use JSON to aggregate strings in SQL Server 2016, as shown in this answer .从评论看来,真正的问题是如何使用 JSON 来聚合 SQL Server 2016 中的字符串,如本答案所示。

SELECT 
 JSON_VALUE(
   REPLACE(
     (SELECT _ = someField FROM someTable FOR JSON PATH)
    ,'"},{"_":"',', '),'$[0]._'
) 

or, rewritten for clarity :或者,为了清楚起见重写:

SELECT 
 JSON_VALUE(  REPLACE(
                    (SELECT _ = someField 
                     FROM someTable 
                     FOR JSON PATH)
              ,'"},{"_":"',', ')
 ,'$[0]._') 

That query works only with string fields.该查询仅适用于字符串字段。 One needs to understand what it does before it can be adopted to other types.在被其他类型采用之前,需要了解它的作用。

  • The inner query generates a JSON string from a field's values, eg '[{"_":"value1"},{"_":"value2"}]' .内部查询从字段的值生成一个 JSON 字符串,例如'[{"_":"value1"},{"_":"value2"}]'
  • REPLACE replaces the quotes and separators between objects, changing that array of objects to '[{"_":"value1,value2"}]' . REPLACE替换对象之间的引号和分隔符,将该对象数组更改为'[{"_":"value1,value2"}]' That's a single object in an array, whose single attribute is a comma-separated string.这是数组中的单个对象,其单个属性是逗号分隔的字符串。
  • JSON_VALUE(...,,'$[0]._') extracts the _ attribute of that single array item. JSON_VALUE(...,,'$[0]._')提取该单个数组项的_属性。

That trick can't be used with numeric values because they don't have quotes.该技巧不能用于数值,因为它们没有引号。 The solution is to cast them to text first:解决方案是先将它们转换为文本:

SELECT 
 JSON_VALUE(  REPLACE(
                    (SELECT _ = CAST(someNumber as nvarchar(20))
                     FROM someTable 
                     FOR JSON PATH)
              ,'"},{"_":"',', ')
 ,'$[0]._') 

Eg :例如:

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]._') 

The only change from the original query is the cast clause.与原始查询的唯一变化是cast子句。

This produces :这产生:

7, 13, 17

This conversion is localized so care must be taken with decimals and dates, to avoid producing unexpected results, eg 38,5, 40,1 instead of 38.5, 40.1 .此转换是本地化的,因此必须注意小数和日期,以避免产生意外结果,例如38,5, 40,1而不是38.5, 40.1

PS: That's no different than the XML technique, except STUFF is used there to cut off the leading separator. PS:这与 XML 技术没有什么不同,只是在那里使用STUFF来切断前导分隔符。 That technique also needs casting numbers to text, eg :该技术需要将数字转换为文本,例如:

SELECT STUFF(
    (  SELECT N', ' + cast(ID as nvarchar(20)) 
       FROM @t FOR XML PATH(''),TYPE)
    .value('text()[1]','nvarchar(max)'),
    1,2,N'')

Yes you could do it with only 2 replace :是的,你可以只用 2 个替换来做到:

SELECT REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','{"_":',''),'}','')

DEMO HERE 演示在这里

Except if you really need a space after coma which is not what you asked to be honest.除非你真的需要一个昏迷后的空间,这不是你要求的诚实。

If you want to use only JSON functions (not string-based approach), the next example may help:如果您只想使用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:结果:

Result
[7,13,17]

Of course, the approach based on string aggregation is also a possible solution:当然,基于字符串聚合的方式也是一种可能的解决方案:

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']'
)   

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM