Multiple rows in one column SQL Server

18,841

Solution 1

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

Solution 2

The entire sub query inside the STUFF() function is evaluated for each row that meets the criteria in the where clause.

In this case you seem to have two rows with ID of 1.

Since the results you want are for the entire set, each row in that set will have the same results, so selecting distinct just helps you hide the duplicates.

If you format your query like this, it will be easier to see why this happens:

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,
    ue.Email
From UserEmail ue
where UserID = 1
Share:
18,841
Maximus Decimus
Author by

Maximus Decimus

Updated on June 07, 2022

Comments

  • Maximus Decimus
    Maximus Decimus almost 2 years

    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]