简体   繁体   English

在 SQL Server 中使用 JSON 连接/聚合字符串

[英]Concatenate/aggregate strings with JSON in SQL Server

This might be a simple question for those who are experienced in working with JSON in SQL Server.对于那些在 SQL Server 中使用 JSON 有经验的人来说,这可能是一个简单的问题。 I found this interesting way of aggregating strings using FOR XML in here .我在这里找到了这种使用FOR XML聚合字符串的有趣方法。

create table #t (id int, name varchar(20))

insert into #t
values (1, 'Matt'), (1, 'Rocks'), (2, 'Stylus')

select  id
    ,Names = stuff((select ', ' + name as [text()]
    from #t xt
    where xt.id = t.id
    for xml path('')), 1, 2, '')
from #t t
group by id

How can I do the same using JSON instead of XML ?如何使用JSON而不是XML来做同样的事情?

You cannot replace the XML approach with JSON.您不能用 JSON 替换 XML 方法。 This string concatenation works due to some XML inner peculiarities, which are not the same in JSON.由于某些 XML 内部特性(在 JSON 中是不同的),因此字符串连接有效。

Starting with SQL Server 2017 onwards you can use STRING_AGG() , but with earlier versions, the XML approach is the way to go.从 SQL Server 2017 开始,您可以使用STRING_AGG() ,但对于早期版本,XML 方法是STRING_AGG()的方法。

Some background and a hint一些背景和提示

First the hint: The code you showed is not safe for the XML special characters.首先提示:您显示的代码对于 XML 特殊字符不安全。 Check my example below.在下面检查我的示例。

First I declare a simple XML首先我声明一个简单的 XML

DECLARE  @xml XML=
N'<a>
  <b>1</b>
  <b>2</b>
  <b>3</b>
  <c>
    <d>x</d>
    <d>y</d>
    <d>z</d>
  </c>
</a>';

--The XPath . ——XPath . tells the XML engine to use the current node (and all within)告诉 XML 引擎使用当前节点(以及所有节点
--Therefore this will return any content within the XML --因此这将返回 XML 中的任何内容

SELECT @xml.value('.','varchar(100)')

--You can specify the path to get 123 or xyz --可以指定获取123或xyz的路径

SELECT @xml.query('/a/b').value('.','varchar(100)')
SELECT @xml.query('//d').value('.','varchar(100)')
    

Now your issue to concatenate tabular data:现在您连接表格数据的问题:

DECLARE @tbl TABLE(SomeString VARCHAR(100));
INSERT INTO @tbl VALUES('This'),('will'),('concatenate'),('magically'),('Forbidden Characters & > <');

--The simple FOR XML query will tag the column with <SomeString> and each row with <row> : -- 简单的FOR XML查询将用<SomeString>标记列,用<row>标记每一行:

SELECT SomeString FROM @tbl FOR XML PATH('row');

--But we can create the same without any tags: --但是我们可以在没有任何标签的情况下创建相同的内容:
--Attention: Look closely, that the result - even without tags - is XML typed and looks like a hyper link in SSMS. --注意:仔细观察,即使没有标签,结果也是 XML 类型的,看起来像 SSMS 中的超链接。

SELECT SomeString AS [*] FROM @tbl FOR XML PATH('');

--Now we can use as a sub-select within a surrounding query. --现在我们可以在周围查询中用作子选择
--The result is returned as string , not XML typed anymore... Look at the forbidden chars! -- 结果以 string形式返回,不再是 XML 类型了...看看禁止的字符!

SELECT
 (SELECT SomeString FROM @tbl FOR XML PATH('row'))
,(SELECT SomeString AS [*] FROM @tbl FOR XML PATH(''))

--We can use ,TYPE to enforce the sub-select to be treated as XML typed itself -- 我们可以使用,TYPE来强制子选择被视为 XML 类型本身
--This allows to use .query() and/or .value() -- 这允许使用.query()和/或.value()

SELECT
 (SELECT SomeString FROM @tbl FOR XML PATH('row'),TYPE).query('data(//SomeString)').value('.','nvarchar(max)')
,(SELECT SomeString AS [*] FROM @tbl FOR XML PATH(''),TYPE).value('.','nvarchar(max)')

XQuery's .data() can be used to concatenate named elements with blanks in between. XQuery 的.data()可用于连接命名元素,中间有空格。
XQuery's .value() must be used to re-escpae forbidden characters. XQuery 的.value()必须用于重新转义禁用字符。

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

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