简体   繁体   English

选择具有最大值的行数

[英]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

dbfiddle here dbfiddle 在这里


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 ;

dbfiddle here dbfiddle 在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM