[英]Selecting a count of rows having a max value
Working example: http://sqlfiddle.com/#!9/80995/20 工作示例: http : //sqlfiddle.com/#!9/80995/20
I have three tables, a user table, a user_group table, and a link table. 我有三个表,一个用户表,一个user_group表和一个链接表。
The link table contains the dates that users were added to user groups. 链接表包含将用户添加到用户组的日期。 I need a query that returns the count of users currently in each group. 我需要一个查询,该查询返回当前每个组中的用户数。 The most recent date determines the group that the user is currently in. 最近的日期确定用户当前所在的组。
SELECT
user_groups.name,
COUNT(l.name) AS ct,
GROUP_CONCAT(l.`name` separator ", ") AS members
FROM user_groups
LEFT JOIN
(SELECT MAX(added), group_id, name FROM link LEFT JOIN users ON users.id = link.user_id GROUP BY user_id) l
ON l.group_id = user_groups.id
GROUP BY user_groups.id
My question is if the query I have written could be optimized, or written better. 我的问题是我编写的查询是否可以优化或编写得更好。
Thanks! 谢谢! Ben 本
You actual query is not giving you the answer you want; 您的实际查询没有给您想要的答案; at least, as far as I understand your question. 至少据我了解您的问题。 John actually joined group 2 on 2017-01-05, yet it appears on group 1 (that he joined on 2017-01-01) on your results. John实际上在2017年1月5日加入了第2组,但在您的结果中却出现在第1组(他于2017年1月1日加入)。 Note also you're missing one Group 4 . 另请注意,您缺少第4组 。
Using standard SQL, I think the next query is what you're looking for. 使用标准SQL,我认为下一个查询就是您要寻找的内容。 The comments in the query should clarify what each part is doing: 查询中的注释应阐明每个部分在做什么:
SELECT
user_groups.name AS group_name,
COUNT(u.name) AS member_count,
group_concat(u.name separator ', ') AS members
FROM
user_groups
LEFT JOIN
(
SELECT * FROM
(-- For each user, find most recent date s/he got into a group
SELECT
user_id AS the_user_id, MAX(added) AS last_added
FROM
link
GROUP BY
the_user_id
) AS u_a
-- Join back to the link table, so that the `group_id` can be retrieved
JOIN link l2 ON l2.user_id = u_a.the_user_id AND l2.added = u_a.last_added
) AS most_recent_group ON most_recent_group.group_id = user_groups.id
-- And get the users...
LEFT JOIN users u ON u.id = most_recent_group.the_user_id
GROUP BY
user_groups.id, user_groups.name
ORDER BY
user_groups.name ;
This can be written in a more compact way in MySQL (abusing the fact that, in older versions of MySQL, it doesn't follow the SQL standard for the GROUP BY
restrictions). 这可以在MySQL中以更紧凑的方式编写(这是因为,在较旧的MySQL版本中,它没有遵循GROUP BY
限制的SQL标准)。
That's what you'll get: 那是您将得到的:
group_name | member_count | members :--------- | -----------: | :------------- Group 1 | 2 | Mikie, Dominic Group 2 | 2 | John, Paddy Group 3 | 0 | null Group 4 | 1 | Nellie
Note that this query can be simplified if you use a database with window functions (such as MariaDB 10.2). 请注意,如果您使用具有窗口功能的数据库(例如MariaDB 10.2),则可以简化此查询。 Then, you can use: 然后,您可以使用:
SELECT
user_groups.name AS group_name,
COUNT(u.name) AS member_count,
group_concat(u.name separator ', ') AS members
FROM
user_groups
LEFT JOIN
(
SELECT
user_id AS the_user_id,
last_value(group_id) OVER (PARTITION BY user_id ORDER BY added) AS group_id
FROM
link
GROUP BY
user_id
) AS most_recent_group ON most_recent_group.group_id = user_groups.id
-- And get the users...
LEFT JOIN users u ON u.id = most_recent_group.the_user_id
GROUP BY
user_groups.id, user_groups.name
ORDER BY
user_groups.name ;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.