【问题标题】:String aggregation using JSON in SQL Server 2016在 SQL Server 2016 中使用 JSON 进行字符串聚合
【发布时间】:2020-03-22 19:06:31
【问题描述】:

我想将 json 字符串 '[{"_":7},{"_":13},{"_":17}]' 格式化为 '[7,13,17]' 尝试在 TSQL 中使用 REPLACE 方法。我必须使用 REPLACE 方法三次才能得到想要的结果。

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

有没有更好的方法来做到这一点? 我正在使用 SQL Server 2016。

在这篇文章的一些 cmet 之后,这是我的实际问题。

我有一些客户数据。客户表

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

兴趣区域表

   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]"
}
]

结果也包含其他一些数据。为了代码简洁,我省略了。

【问题讨论】:

  • 您既没有格式化也没有替换。您正在查询一个对象数组,提取属性值并将它们作为数组本身返回。您需要为此编写查询
  • @PanagiotisKanavos 我正在按照他的方法生成该输出。 stackoverflow.com/a/42778050/764369
  • 这与 JSON 无关。您正在询问如何在 SQL Server 2016 中聚合字符串。This answer 对该问题显示了正确的查询,尽管它 not 与常见的 XML 方法不同。无需更换,
  • 发布 actual 问题、actual 数据和 actual 输出。如果您对该查询的结果有疑问,添加额外的 REPLACE 语句不会解决问题。
  • 您需要更少个替代品,而不是更多。链接的答案适用于引用的 string 值。您在问如何使用不是的 numeric 值。您需要删除一些引号。或者只是使用 XML 技术

标签: sql json sql-server tsql sql-server-2016


【解决方案1】:

短版

在尝试聚合之前将数字字段转换为文本


从 cmets 看来,真正的问题是如何在 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'')

【讨论】:

  • 解释得很好。我已根据您的要求更新了问题。
  • 在我对一个大数据集的测试中,并在SELECT 语句中包含一个WHERE 子句来聚合每个主记录的详细记录,FOR JSON 版本比@987654340 快大约 20% @,并且对 & 和 > 等特殊字符进行编码没有问题。
【解决方案2】:

如果您只想使用 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']'
)   

【讨论】:

  • OP 已经在尝试使用基于 JSON 的字符串聚合技术
【解决方案3】:

是的,您只需更换 2 次即可:

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

DEMO HERE

除非您在昏迷后确实需要一个空格,这不是您说实话。

【讨论】:

  • 大多数人在coma 之后需要一些空间。大脑需要一段时间才能重新适应清醒。
猜你喜欢
  • 2020-03-23
  • 2020-04-05
  • 1970-01-01
  • 2019-03-27
  • 2021-03-28
  • 2021-05-06
  • 2011-03-23
  • 2018-05-24
  • 2018-10-12
相关资源
最近更新 更多