views:

55

answers:

1

I have a query that returns a result set of one column, but I want it to be converted into one long string for use as a subquery. I.E. I want to be able to do:

SELECT user.*, (SELECT group_name FROM user_groups WHERE userID = user.ID) AS Groups FROM user

However, that will fail because a user can belong to more than one group. For example if the user belong to {"writer", "editor"} I want it to return a string like this: "writer, editor".

How can I do this?

+1  A: 

You can use FOR XML to do this pivoting action. Here is a working sample.

set nocount on

declare @Users Table
(
    UserId  int,
    UserName varchar (20)
)

declare @UserGroups Table
(
GroupId int,
UserId int,
GroupName varchar (20)
)

Insert @Users Values (1, 'Tim')
Insert @Users Values (2, 'Jane')
Insert @Users Values (3, 'Hal')

Insert @UserGroups Values (1, 1, 'Admin')
Insert @UserGroups Values (2, 1, 'Power-users')
Insert @UserGroups Values (3, 2, 'Noobs')
Insert @UserGroups Values (4, 2, 'Users')
Insert @UserGroups Values (5, 3, 'Noobs')

/* How this works */

SELECT 'FirstStep  : Users table'
SELECT * FROM @Users

SELECT 'NextStep : User Groups table'
SELECT * FROM @UserGroups

SELECT 'NextStep : Users & UserGroups table'
SELECT * 
FROM @Users U
    INNER JOIN @UserGroups UG ON U.UserId = UG.UserId

SELECT 'NextStep : Just get the groups for one user (UserId = 2)'
SELECT GroupName
FROM @UserGroups UG
WHERE UG.userID = 2
ORDER BY GroupName

SELECT 'NextStep : When you use XML Path the output comes out in XML format'
SELECT GroupName
FROM @UserGroups UG
WHERE UG.userID = 2
ORDER BY GroupName
FOR XML PATH('') -- XML Path added

SELECT 'NextStep : When you remove the column name the XML tags go away, 
but it looks ugly because there is no separator' 
SELECT GroupName + '' -- Added an empty string to remove the column name
FROM @UserGroups UG
WHERE UG.userID = 2
ORDER BY GroupName
FOR XML PATH('') 

SELECT 'NextStep : Add a separator
We add it to the beginning instead of the end so that we can STUFF later on.' 
SELECT ', ' + GroupName -- Added an empty string to remove the column name
FROM @UserGroups UG
WHERE UG.userID = 2
ORDER BY GroupName
FOR XML PATH('') 

SELECT 'NextStep : I don''t like that ugly XML column name. Let me give it my own name' 
SELECT 
(
    SELECT ', ' + GroupName
    FROM @UserGroups UG
    WHERE UG.userID = 2
    ORDER BY GroupName
    FOR XML PATH('') 
) as UserGroups

SELECT 'NextStep : STUFF the extra comma' 
SELECT STUFF 
    (
        (
            SELECT ', ' + GroupName
            FROM @UserGroups UG
            WHERE UG.userID = 2
            ORDER BY GroupName
            FOR XML PATH('') 
        ),
        1, 2, ''
    ) as UserGroups


SELECT 'NextStep : Now join it with the Users table by the UserId and get the UserName' 
SELECT 
    U.UserName, 
    STUFF 
    (
        (
            SELECT ', ' + GroupName
            FROM @UserGroups UG
            WHERE UG.userID = U.userID
            ORDER BY GroupName
            FOR XML PATH('') 
        ),
        1, 2, ''
    ) as UserGroups
FROM @Users U
Raj More
how does this work?
Malfist
@Malfist, I added a step by step explanation
Raj More
okay, I see. So if the column doesn't have a name the FOR XML with no path just prints out the values
Malfist