工作示例:http://sqlfiddle.com/#!9/80995/20
我有三个表,一个用户表,一个user_group表和一个链接表。
链接表包含用户添加到用户组的日期。我需要一个返回每组中当前用户数的查询。最近的日期决定了用户当前所在的组。
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
我的问题是,我写的查询是否可以优化,或写得更好。
谢谢! 本
答案 0 :(得分:2)
您的实际查询并未提供您想要的答案;至少,据我了解你的问题。 John 实际上在2017-01-05加入了第2组,但它出现在第1组(他于2017-01-01加入)中。另请注意,您缺少一个 Group 4 。
使用标准SQL,我认为下一个查询是您正在寻找的。查询中的注释应阐明每个部分正在做什么:
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 ;
这可以在MySQL中以更紧凑的方式编写(滥用这一事实,在旧版本的MySQL中,它不遵循GROUP BY
限制的SQL标准。
这就是你会得到的:
group_name | member_count | members :--------- | -----------: | :------------- Group 1 | 2 | Mikie, Dominic Group 2 | 2 | John, Paddy Group 3 | 0 | null Group 4 | 1 | Nellie
dbfiddle here
请注意,如果您使用带有窗口函数的数据库(例如MariaDB 10.2),则可以简化此查询。然后,您可以使用:
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 ;
dbfiddle here