90

I have a SQL query like this;

SELECT * 
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534
AND ISSUE = 19602

And that's the results;

enter image description here

What I want is; showing in one row (cell) combined all STRINGVALUE's and they are separated with a comma. Like this;

SELECT --some process with STRINGVALUE--
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534
AND ISSUE = 19602

Araç Listesi (C2, K1 vb.Belgeler; yoksa Ruhsat Fotokopileri), Min. 5
araç plakası için İnternet Sorgusu, Son 3 Yıla Ait Onaylı Yıl Sonu
Bilanço + Gelir Tablosu, Son Yıl (Yıl Sonuna ait) Detay Mizanı, İçinde
Bulunduğumuz Yıla ait Ara Dönem Geçici Vergi Beyannamesi, Bayi Yorum
E-Maili, Proforma Fatura

How can I do that?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
  • a.k.a. how to violate 1NF i.e. this is not easy to do in SQL (a smell) by design because it involves generating a non-relational result. Instead do this in a reporting tool, front end code, etc. – onedaywhen Nov 04 '11 at 08:48

8 Answers8

103

There are several methods.

If you want just the consolidated string value returned, this is a good quick and easy approach

DECLARE @combinedString VARCHAR(MAX)
SELECT @combinedString = COALESCE(@combinedString + ', ', '') + stringvalue
FROM jira.customfieldValue
WHERE customfield = 12534
    AND ISSUE = 19602

SELECT @combinedString as StringValue 

Which will return your combined string.

You can also try one of the XML methods e.g.

SELECT DISTINCT Issue, Customfield, StringValues
FROM Jira.customfieldvalue v1
CROSS APPLY ( SELECT StringValues + ',' 
              FROM jira.customfieldvalue v2
              WHERE v2.Customfield = v1.Customfield 
                  AND v2.Issue = v1.issue 
              ORDER BY ID 
                  FOR XML PATH('') )  D ( StringValues )
WHERE customfield = 12534
    AND ISSUE = 19602
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Code Magician
  • 23,217
  • 7
  • 60
  • 77
  • 2
    There is a very good tutorial here https://www.mssqltips.com/sqlservertip/2914/rolling-up-multiple-rows-into-a-single-row-and-column-for-sql-server-data/ – Thomas Gak-Deluen Mar 19 '18 at 14:32
  • If you are going to run this query from PHP, be sure to declare the @combinedstring as fixed length varchar: `DECLARE @combinedString VARCHAR(255)` – Jan Jun 30 '18 at 12:05
29

You can achieve this is to combine For XML Path and STUFF as follows:

SELECT (STUFF((
        SELECT ', ' + StringValue
        FROM Jira.customfieldvalue
        WHERE CUSTOMFIELD = 12534
        AND ISSUE = 19602
        FOR XML PATH('')
        ), 1, 2, '')
    ) AS StringValue
Karthikeyan P
  • 1,216
  • 1
  • 20
  • 23
14

This is an old question, but as of the release of Microsoft SQL Server 2017 you can now use the STRING_AGG() function which is much like the GROUP_CONCAT function in MySQL.

STRING_AGG (Transact-SQL) Documentation

Example

USE AdventureWorks2016
GO
SELECT STRING_AGG (CONVERT(NVARCHAR(max),FirstName), ',') AS csv 
FROM Person.Person; 

Returns

Syed,Catherine,Kim,Kim,Kim,Hazem
Fütemire
  • 1,705
  • 1
  • 26
  • 21
9

There's a convenient method for this in MySql called GROUP_CONCAT. An equivalent for SQL Server doesn't exist, but you can write your own using the SQLCLR. Luckily someone already did that for you.

Your query then turns into this (which btw is a much nicer syntax):

SELECT CUSTOMFIELD, ISSUE, dbo.GROUP_CONCAT(STRINGVALUE)
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534 AND ISSUE = 19602
GROUP BY CUSTOMFIELD, ISSUE

But please note that this method is good for at the most 100 rows within a group. Beyond that, you'll have major performance problems. SQLCLR aggregates have to serialize any intermediate results and that quickly piles up to quite a lot of work. Keep this in mind!

Interestingly the FOR XML doesn't suffer from the same problem but instead uses that horrendous syntax.

Fabrice
  • 3,094
  • 3
  • 28
  • 31
John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • I have a situation where this will only group two or three rows at max, so this is perfect for me in its simplicity. Seeing as this answer is a few years old, has performance of this method improved? – Christian Nov 22 '17 at 10:45
  • 1
    I know this was posted in 2011, but as of SQL 2017 you can now use the `STRING_AGG()` function, which is like MySQL `GROUP_CONCAT()` is you want to update your answer. ;) – Fütemire May 10 '21 at 15:59
1

I believe for databases which support listagg function, you can do:

select id, issue, customfield, parentkey, listagg(stingvalue, ',') within group (order by id)
from jira.customfieldvalue
where customfield = 12534 and issue = 19602
group by id, issue, customfield, parentkey
Liang
  • 361
  • 3
  • 9
0
CREATE VIEW  [dbo].[ret_vwSalariedForReport]
AS
     WITH temp1 AS (SELECT
     salaried.*,
     operationalUnits.Title as OperationalUnitTitle
FROM
    ret_vwSalaried salaried LEFT JOIN
    prs_operationalUnitFeatures operationalUnitFeatures on salaried.[Guid] = operationalUnitFeatures.[FeatureGuid] LEFT JOIN 
    prs_operationalUnits operationalUnits ON operationalUnits.id = operationalUnitFeatures.OperationalUnitID 
    ), 
temp2 AS (SELECT
    t2.*,
    STUFF ((SELECT ' - ' + t1.OperationalUnitTitle
        FROM
            temp1 t1 
        WHERE t1.[ID] = t2.[ID]  
        For XML PATH('')), 2, 2, '') OperationalUnitTitles from temp1 t2) 
SELECT 
    [Guid],
    ID,
    Title,
    PersonnelNo,
    FirstName,
    LastName,
    FullName,
    Active,
    SSN,
    DeathDate,
    SalariedType,
    OperationalUnitTitles
FROM 
    temp2
GROUP BY 
    [Guid],
    ID,
    Title,
    PersonnelNo,
    FirstName,
    LastName,
    FullName,
    Active,
    SSN,
    DeathDate,
    SalariedType,
    OperationalUnitTitles
mehrab habibi
  • 427
  • 1
  • 5
  • 16
0

declare @maxColumnCount int=0;
 declare @Query varchar(max)='';
 declare @DynamicColumnName nvarchar(MAX)='';

-- table type variable that store all values of column row no
 DECLARE @TotalRows TABLE( row_count int)
 INSERT INTO @TotalRows (row_count)
 SELECT (ROW_NUMBER() OVER(PARTITION BY InvoiceNo order by InvoiceNo Desc)) as row_no FROM tblExportPartProforma

-- Get the MAX value from @TotalRows table
 set @maxColumnCount= (select max(row_count) from @TotalRows)
 
-- loop to create Dynamic max/case and store it into local variable 
 DECLARE @cnt INT = 1;
 WHILE @cnt <= @maxColumnCount
 BEGIN
   set @DynamicColumnName= @DynamicColumnName + ', Max(case when row_no= '+cast(@cnt as varchar)+' then InvoiceType end )as InvoiceType'+cast(@cnt as varchar)+''
      set @DynamicColumnName= @DynamicColumnName + ', Max(case when row_no= '+cast(@cnt as varchar)+' then BankRefno end )as BankRefno'+cast(@cnt as varchar)+''
            set @DynamicColumnName= @DynamicColumnName + ', Max(case when row_no= '+cast(@cnt as varchar)+' then AmountReceived end )as AmountReceived'+cast(@cnt as varchar)+''

      set @DynamicColumnName= @DynamicColumnName + ', Max(case when row_no= '+cast(@cnt as varchar)+' then AmountReceivedDate end )as AmountReceivedDate'+cast(@cnt as varchar)+''


   SET @cnt = @cnt + 1;
END;

-- Create dynamic CTE and store it into local variable @query 
  set @Query='
     with CTE_tbl as
     (
       SELECT InvoiceNo,InvoiceType,BankRefno,AmountReceived,AmountReceivedDate,
       ROW_NUMBER() OVER(PARTITION BY InvoiceNo order by InvoiceNo Desc) as row_no
       FROM tblExportPartProforma
      )
  select
     InvoiceNo
     '+@DynamicColumnName+'
     FROM CTE_tbl
     group By InvoiceNo'

-- Execute the Query
 execute (@Query)
Anand
  • 1
-1

Using MySQL inbuilt function group_concat() will be a good choice for getting the desired result. The syntax will be -

SELECT group_concat(STRINGVALUE) 
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534
AND ISSUE = 19602

Before you execute the above command make sure you increase the size of group_concat_max_len else the the whole output may not fit in that cell.

To set the value of group_concat_max_len, execute the below command-

SET group_concat_max_len = 50000;

You can change the value 50000 accordingly, you increase it to a higher value as required.

Rito
  • 3,092
  • 2
  • 27
  • 40
  • Thanks but sorry, my question was for "T-SQL" as you can see. Your answer was _also_ included in [Combine Multiple child rows into one row MYSQL](http://stackoverflow.com/q/1067428/447156) by the way. – Soner Gönül Aug 01 '16 at 13:18