Multiple rows in one column SQL Server

Maximus Decimus picture Maximus Decimus · Nov 18, 2013 · Viewed 18.5k times · Source

I want to concatenate multiple rows in one column. I found many examples in Internet but does not working for me. What am I doing wrong?

        SELECT UserID,  
        STUFF((SELECT '; ' + Email.Email From Email where  UserEmail.EmailID = Email.ID for xml path('')),1,1, '') AS Emails
        From UserEmail
        where UserID = 1

I'm still having the information like this

UserID  Email
1       [email protected]
1       [email protected] 

--EDIT--

Ok, I did this change but still having 2 rows. If I apply distinct this will fix my problem but why do I have to use distinct. The query must group it by itself.

        SELECT UserID,  
        STUFF(( SELECT '; ' + ea.Email 
                From Email ea inner join UserMail ue_inner on ue_inner.EmailID = ea.ID 
                where 
                ue_inner.UserID = ue.UserID
                for xml path('')), 1, 1, '') 
                AS Email
        From UserEmail ue
        where UserID = 1

Results

UserID   Email 
1        [email protected]; [email protected]
1        [email protected]; [email protected]

Answer

Roman Pekar picture Roman Pekar · Nov 19, 2013

Unfortunately, SQL Server doesn't have proper string concatenation, so you cannot concatenate strings while grouping. So there're several possible solutions.

1. If you want to concatenate data for single ID, you can use variable trick:

declare @Emails varchar(max)

select @Emails = isnull(@Emails + ', ', '') + E.Email
from Email as E
    inner join UserEmail as UE on UE.EmailID = E.EmailID
where UE.UserID = 1

select @Emails;

-----------------
[email protected], [email protected]

2. If you want to do proper grouping, you can use xml trick. So, basic idea is - you get distinct UserID as anchor query (using group by), and then concatenate data in the subquery. Important thing is to do this correctly, use for xml ... type and get concatenated string as .value(), so special characters will be treated correctly:

select
    UE.UserID,
    stuff(
        (
            select ', ' + TE.Email
            from Email as TE
                inner join UserEmail as TUE on TUE.EmailID = TE.EmailID
            where TUE.UserID = UE.UserID
            for xml path(''), type
        ).value('.', 'varchar(max)')
    , 1, 2, '') as Emails
from UserEmail as UE
group by UE.UserID

See sql fiddle demo with examples: sql fiddle demo