Reputation: 1043
I have got 3 tables (only important for question columns here):
USERS GROUPS USERS_GROUPS
id id user_id
importance group_id
color
As you can see, one user can be in many groups, each group has got different color, some groups are more important than others. For example user A is in group editor (blue color) and moderator (green color). What color he should be visible as? In green, because moderator is more important than editor.
But I have no idea (maybe it isn't possible in one query?) how to get user's color from table groups. I have created such query:
SELECT * FROM `users` INNER JOIN users_groups ON users_groups.user_id = users.id INNER JOIN groups ON groups.id=users_groups.group_id
But it returns as many user's rows as user has group, like that:
USERNAME (...) GROUP_ID NAME (group) COLOR IMPORTANCE
user 2 moderator green 50
user 3 editor blue 25
administrator 1 admin orange 100
administrator 3 editor blue 25
I would like to get only most important group - administrator as member of group admin and user as member of group moderator.
Upvotes: 3
Views: 398
Reputation: 349
Option 1:
This one gets the most important group for each user and then goes back into the groups
table to find the color for that group. The additional JOIN is needed because the initial GROUP BY will not necessarily grab the correct color corresponding with the MAX(importance) result.
SELECT T1.*, groups.color FROM
(
SELECT users.id, MAX(groups.importance) AS most_important_group FROM `users`
INNER JOIN
users_groups
ON users_groups.user_id = users.id
INNER JOIN groups
ON groups.id=users_groups.group_id
GROUP BY users.id
) AS T1
INNER JOIN
groups
ON T1.most_important_group=groups.importance
GROUP BY T1.id
Option 2: This option orders the initial result set in a way which should bring each users' highest importance group to the top along with the corresponding color from that row. After the outer GROUP BY, you should only see one row for each user containing the info you want. You can customize which fields to return from the subquery. I included as many as possible, but you should whittle these down if you don't need them (fewer fields should mean a faster result).
SELECT * FROM
(
SELECT users.*, users_groups.*, groups.importance, groups.color FROM `users`
INNER JOIN users_groups
ON users_groups.user_id = users.id
INNER JOIN groups
ON groups.id=users_groups.group_id
ORDER BY users.id, groups.importance DESC
) AS T1
GROUP BY T1.id
The performance of these will vary depending on your table sizes and definitely with your index structure. Try them both and respond with which one is faster. If you need faster run time, feel free to respond with some EXPLAIN statements from these queries and DESCRIBE statements about the tables.
Upvotes: 1
Reputation: 8349
This is a fairly common problem in mysql which has several different solutions, the generally fastest is to join to a subquery which selects the highest importance to filter the results.
SELECT users.*, groups.*
FROM `users`
INNER JOIN users_groups
ON users_groups.user_id = users.id
INNER JOIN groups
ON groups.id=users_groups.group_id
INNER JOIN (SELECT user_groups.user_id, MAX(importance) AS importance FROM groups GROUP BY user_id) mxGrp
ON (groups.user_id = mxGrp.user_id AND groups.importance = mxGrp.importance);
Read this blog post for discussion about other possible solutions.
Upvotes: 1