Coder Perfect

ListAGG in SQLSERVER

Problem

In SQLServer, I’m attempting to aggregate a ‘STRING’ field. I’m looking for a function similar to Oracle’s LISTAGG.

Do you know how to perform the same function in a different way?

For Example,

Field A | Field B
1       |  A
1       |  B
2       |  A

And I’d like the query’s result to be as follows:

1 | AB
2 | A

Asked by user1557642

Solution #1

SELECT FieldA
     , GROUP_CONCAT(FieldB ORDER BY FieldB SEPARATOR ',') AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;
SELECT FieldA
     , LISTAGG(FieldB, ',') WITHIN GROUP (ORDER BY FieldB) AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;
SELECT FieldA
     , STRING_AGG(FieldB, ',' ORDER BY FieldB) AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

SQL Server 2017 and Azure SQL Database

SELECT FieldA
     , STRING_AGG(FieldB, ',') WITHIN GROUP (ORDER BY FieldB) AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

SQL Server 2016 is the latest version of SQL Server (CTE included to encourage the DRY principle)

  WITH CTE_TableName AS (
       SELECT FieldA, FieldB
         FROM TableName)
SELECT t0.FieldA
     , STUFF((
       SELECT ',' + t1.FieldB
         FROM CTE_TableName t1
        WHERE t1.FieldA = t0.FieldA
        ORDER BY t1.FieldB
          FOR XML PATH('')), 1, LEN(','), '') AS FieldBs
  FROM CTE_TableName t0
 GROUP BY t0.FieldA
 ORDER BY FieldA;

Ordering requires a CTE or subquery

  WITH CTE_TableName AS (
       SELECT FieldA, FieldB
         FROM TableName
        ORDER BY FieldA, FieldB)
SELECT FieldA
     , GROUP_CONCAT(FieldB, ',') AS FieldBs
  FROM CTE_TableName
 GROUP BY FieldA
 ORDER BY FieldA;

Without ordering

SELECT FieldA
     , GROUP_CONCAT(FieldB, ',') AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

Answered by Manas Kumar

Solution #2

The STRING AGG function is included in SQL Server 2017 and simplifies the logic significantly:

select FieldA, string_agg(FieldB, '') as data
from yourtable
group by FieldA

Demonstration of SQL Fiddle

To get the following result in SQL Server, use FOR XML PATH:

select distinct t1.FieldA,
  STUFF((SELECT distinct '' + t2.FieldB
         from yourtable t2
         where t1.FieldA = t2.FieldA
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,0,'') data
from yourtable t1;

Demonstration of SQL Fiddle

Answered by Taryn

Solution #3

STRING AGG is a new feature in SQL Server 2017:

SELECT t.name,STRING_AGG (c.name, ',') AS csv
FROM sys.tables t
JOIN sys.columns c on t.object_id = c.object_id
GROUP BY t.name
ORDER BY 1

Also available in SQL Server 2016 is STRING SPLIT, which is beneficial in the opposite circumstance.

Answered by vldmrrdjcc

Solution #4

This could be valuable to someone else as well…

For the purposes of a data analyst and data profiling, for example (i.e. not grouped by)

Prior to the introduction of the SQL*Server 2017 String agg function…

(That is, it only returns one row..)

select distinct
SUBSTRING (
stuff(( select distinct ',' + [FieldB] from tablename order by 1 FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') 
,1,0,'' ) 
,2,9999)
from 
    tablename 

For example, yields the comma-separated values A,B.

Answered by Allan F

Post is based on https://stackoverflow.com/questions/15477743/listagg-in-sqlserver