2017-07-31 163 views
0

工作示例行數: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

所以你實際上並不需要的GROUP_CONCAT? – Strawberry

+0

這將是很好的顯示用戶列表,但我可以削減功能,如果它會產生很大的差異 – Ben

回答

2

你實際的查詢並沒有給你你想要的答案;至少,據我瞭解你的問題。 約翰實際上在2017-01-05加入了第2組,但它出現在第1組(他加入2017-01-01)上。請注意,您還缺少一個組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,它不會遵循SQL標準爲GROUP BY限制)。

這就是你會得到什麼:

 
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

+2

@Ben這裏提供的第一個解決方案是完全一樣,我會這樣做,而且可能是最佳的。任何進一步的改進將取決於對索引的孜孜以求。 – Strawberry

+0

非常感謝!如果它沒有太多的痛苦,你能否給我一個關於爲什麼我的查詢不能正常工作的指針? – Ben