Reputation: 317
I have three tables: Projects, ProjectAccess and Users:
+-----------+----------------+
| IdProject | Project Name |
+-----------+----------------+
| 1 | First Project |
| 2 | Second Project |
| 3 | Third Project |
+-----------+----------------+
+-----------+---------+
| IdProject | IdUsers |
+-----------+---------+
| 1 | 2 |
| 1 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
+-----------+---------+
+---------+----------+
| IdUsers | Username |
+---------+----------+
| 1 | Tom |
| 2 | Dick |
| 3 | Harry |
| 4 | Bob |
+---------+----------+
I want to write a query that returns a row from Projects that includes a field with all the comma separated usernames of user accounts that have access to that project (as defined in ProjectAccess). i.e. Results look like this:
+-----------+----------------+------------------+
| IdProject | ProjectName | Users w/ Access |
+-----------+----------------+------------------+
| 1 | First Project | Tom, Dick |
| 2 | Second Project | Dick, Harry, Bob |
| 3 | Third Project | |
+-----------+----------------+------------------+
I understand I have to join the tables together and use STUFF in the select, I'm not sure how exactly to accomplish this.
Anyone point me in the right direction?
Thanks
Upvotes: 0
Views: 2912
Reputation: 364
Try the following query-:
select IdProject,[Project Name],[Users w/ Access]= COALESCE(STUFF((
select Distinct ','+ Username
from Users a
join ProjectAccess b
on a.IdUsers =b.IdUsers
and b.IdProject =p.IdProject
FOR XML PATH ('')), 1, 1, ''
),'') from Projects p
SQL Server
Upvotes: 0
Reputation: 1791
You can achieve this fairly simply using the STRING_AGG function as such:
SELECT p.Id, p.projectName , STRING_AGG(u.Name, ', ') Names
FROM project p
JOIN projectAccess AS pa ON p.Id = pa.Id
JOIN users AS u on pa.userId = u.userId
GROUP BY p.Id, p.projectName
Here is a demo of this in action: SQLFiddle
EDIT: You can change both joins to a left join if you want to see the empty third project. Demo of this: SQLFiddle
Upvotes: 0
Reputation: 14189
You can use STUFF with FOR XML
as correlated subquery.
SELECT
IdProject = P.IdProject,
[Project Name] = P.[Project Name],
[Users w/ Access] = STUFF (
(
SELECT
', ' + U.Username
FROM
ProjectAccess AS A
INNER JOIN Users AS U ON A.IdUsers = U.IdUsers
WHERE
A.IdProject = P.IdProject -- Link the correlated query with the outmost Project (P) table
FOR XML
PATH ('')
),
1, -- Replace a string that starts at position number 1 (first character)
2, -- for the next 2 characters (the leading ', ')
'') -- with an empty string
FROM
Projects AS P
This basically lists all projects but for each one, retrieves a comma separated list of each related username. The STUFF
function replaces the leading comma while the FOR XML
clause makes the subquery actually return 1 row with 1 value instead of a full table.
Upvotes: 3
Reputation: 37473
Try this query:
select idprojects,projectsname,STRING_AGG(username, ',') from
(
select a.idprojects, a.projectname,c.username
from
Projects a inner join ProjectAccess b
on a.idprojects=b.idprojects inner join Users c
on b.idusers=c.idusers)x
group by idprojects,projectsname
Upvotes: 1