简体   繁体   中英

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. I found this interesting way of aggregating strings using FOR XML in here .

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 ?

You cannot replace the XML approach with JSON. This string concatenation works due to some XML inner peculiarities, which are not the same in JSON.

Starting with SQL Server 2017 onwards you can use STRING_AGG() , but with earlier versions, the XML approach is the way to go.

Some background and a hint

First the hint: The code you showed is not safe for the XML special characters. Check my example below.

First I declare a simple 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 . tells the XML engine to use the current node (and all within)
--Therefore this will return any content within the XML

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

--You can specify the path to get 123 or 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> :

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.

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!

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
--This allows to use .query() and/or .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's .value() must be used to re-escpae forbidden characters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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