MySQL - select rank for users in a score table

拟墨画扇 提交于 2019-12-12 15:31:27

问题


I've got a 'user_score' table with that structure:

|id|user_id|group_id|score|     timestamp      |
| 1|      1|       1|  500| 2013-02-24 18:00:00|
| 2|      2|       1|  200| 2013-02-24 18:01:50|
| 3|      1|       2|  100| 2013-02-24 18:06:00|
| 4|      1|       1| 6000| 2013-02-24 18:07:30|

What I need to do is to select all users from that table which are from the exact group. Select their actual (according to timestamp) score in that group and their rank.

What I have is (edit: after Jocachin's comment I found out that my own query does not work as I expected, sorry to all):

SELECT user_id, score, @curRank := @curRank + 1 AS rank
FROM (
    SELECT * 
    FROM (
           SELECT * FROM `user_score`
           WHERE `group_id` = 1
           ORDER BY `timestamp` DESC
    ) AS sub2
    GROUP BY `user_id`
) AS sub, (SELECT @curRank := 0) r
ORDER BY `rank`

Expected result for example data and group_id = 1:

|user_id|score|rank|
|      1| 6000|   1|
|      2|  200|   2|

But MySQL subselects are a bit problematic, do you see any other solution, please?

I'll probably need to get the rank od single user in the group later. I am lost at the moment.


回答1:


Although I'm not sure what "problematic" means in this context, here is the query rewritten as a plain LEFT JOIN with a subquery just to get the ranking right at the end (the ORDER BY needs to be done before the ranking);

SELECT user_id, score, @rank := @rank + 1 AS rank FROM
(
  SELECT u.user_id, u.score
  FROM user_score u
  LEFT JOIN user_score u2
    ON u.user_id=u2.user_id
   AND u.`timestamp` < u2.`timestamp`
  WHERE u2.`timestamp` IS NULL
  ORDER BY u.score DESC
) zz, (SELECT @rank := 0) z;

An SQLfiddle to test with.

EDIT: To take group_id into account, you'll need to extend the query somewhat;

SELECT user_id, score, @rank := @rank + 1 AS rank FROM
(
  SELECT u.user_id, u.score
  FROM user_score u
  LEFT JOIN user_score u2
    ON u.user_id=u2.user_id
   AND u.group_id = u2.group_id       -- u and u2 have the same group
   AND u.`timestamp` < u2.`timestamp`
  WHERE u2.`timestamp` IS NULL
    AND u.group_id = 1                -- ...and that group is group 1
  ORDER BY u.score DESC
) zz, (SELECT @rank := 0) z;

Another SQLfiddle.




回答2:


SELECT user_id, score, @rank := @rank + 1 AS rank 
FROM 
(
    SELECT 
        user_id AS user_id, 
        SUBSTRING_INDEX(GROUP_CONCAT(score ORDER BY timestamp DESC), ',', 1) 
            AS score 
    FROM user_score 
    WHERE group_id=1 
    GROUP BY user_id
) AS u, 
(
    SELECT @rank := 0
) AS r
ORDER BY score DESC;



回答3:


I know an answer has been posted and accepted but I have a point about your original query that I think is worth mentioning.

When you group by, you are only allowed to select the columns you group by and those with aggregate functions such as MAX and COUNT. Selecting other columns is technically wrong.

This makes sense since it is not clear the data of which row should be returned. Mysql returns the data of the first row in group by; that is why your query works (because of the order by timestamp in the inner sub query). SQL server on the other hand raises an exception.

I think SQL Server approach is correct and this type of query should be avoided.




回答4:


I ran into a similar problem today and after unsuccessfully trying to implement the accepted answer I did this much simpler query

SELECT user_score.user_id, 
       MAX(user_score.score) AS score
FROM user_score 
WHERE user_score.group_id = 1 
GROUP BY user_score.user_id, 
         user_score.group_id
ORDER BY user_score.score DESC, 
         user_score.`timestamp` ASC


来源:https://stackoverflow.com/questions/15054456/mysql-select-rank-for-users-in-a-score-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!