3

我有一个具有该结构的“user_score”表:

|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|

我需要做的是从该表中选择来自确切组的所有用户。选择他们在该组中的实际(根据时间戳)得分和排名。

我所拥有的是(编辑:在 Jocachin 发表评论后,我发现我自己的查询没有按预期工作,对所有人感到抱歉):

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`

示例数据和 group_id = 1 的预期结果:

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

但是 MySQL 子选择有点问题,请问您还有其他解决方案吗?

稍后我可能需要在组中获得排名 od 单个用户。我现在迷路了。

4

4 回答 4

5

尽管我不确定在这种情况下“有问题”是什么意思,但这里的查询被重写为LEFT JOIN带有子查询的普通查询,只是为了在最后获得正确的排名(ORDER BY需要在排名之前完成);

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;

一个用于测试的 SQLfiddle

编辑:要考虑 group_id ,您需要稍微扩展查询;

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;

另一个 SQLfiddle

于 2013-02-24T17:50:48.817 回答
1

我知道答案已发布并被接受,但我认为您的原始查询有一点值得一提。

分组依据时,只能选择分组依据的列以及具有 MAX 和 COUNT 等聚合函数的列。选择其他列在技术上是错误的。

这是有道理的,因为不清楚应该返回哪一行的数据。mysql返回group by中第一行的数据;这就是您的查询有效的原因(因为内部子查询中按时间戳排序)。另一方面,SQL 服务器引发异常。

我认为 SQL Server 方法是正确的,应该避免这种类型的查询。

于 2013-02-24T19:35:20.503 回答
1
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;
于 2013-02-24T17:51:36.817 回答
0

我今天遇到了类似的问题,在尝试实现接受的答案失败后,我做了这个更简单的查询

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
于 2018-05-29T18:53:45.340 回答