I have four tables Users, Roles, User_Role, and Email. I need to develop a query that retrieves the user information (username, lastname, and firstname), the users email address (from the email table) and an aggregated list of all the roles (which is connected to the User tables with a many-to-many table user_role). I developed the query below which has one problem. The aggregated list has duplicate role name entries.
SELECT DISTINCT ON (u.username)
u.username AS "Username", u.lastname AS "Last Name", u.firstname AS "First Name", e.name AS "Email Address"
, string_agg(r.name, ';' ORDER BY r.name) AS "Roles"
FROM users u
LEFT OUTER JOIN user_role ur ON (u.id=ur.user_id)
LEFT OUTER JOIN roles r ON (ur.role_id = r.id)
INNER JOIN email e ON e.user_id = u.id
WHERE u.active = 1 AND length(r.name) > 0 AND r.active = 1 AND ur.active = 1
GROUP BY u.username, u.lastname, u.firstname, e.name
ORDER BY u.username
If I comment out the Inner email join and associated email fields (see below) I get the correct role names in the string_agg.
SELECT DISTINCT ON (u.username)
u.username AS "Username", u.lastname AS "Last Name", u.firstname AS "First Name",
-- e.name AS "Email Address"
, string_agg(r.name, ';' ORDER BY r.name) AS "Roles"
FROM users u
LEFT OUTER JOIN user_role ur ON (u.id=ur.user_id)
LEFT OUTER JOIN roles r ON (ur.role_id = r.id)
-- INNER JOIN email e ON e.user_id = u.id
WHERE u.active = 1 AND length(r.name) > 0 AND r.active = 1 AND ur.active = 1
GROUP BY u.username, u.lastname, u.firstname,
-- e.name
ORDER BY u.username