【问题标题】:Calculate Rank for users based on groups and score根据组和分数计算用户的排名
【发布时间】:2020-01-22 07:11:10
【问题描述】:

我看到有很多类似的问题,但我已经耗尽了我找到的所有解决方案。它们都没有像我预期的那样工作。

我的场景如下:

  1. 带有用户分数的表格(其他数据被剥离,不相关):
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| user_id      | int(11)      | NO   | MUL | NULL    |                |
| score        | int(11)      | NO   |     | NULL    |                |
| rank         | int(11)      | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+
  1. 带有用户的表格(其他数据被剥离,不相关):
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| group_id        | int(11)      | NO   | MUL | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+
  1. 带有组的表格(其他数据被剥离,不相关):
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| name         | varchar(100) | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+

要求是:

  1. 根据 100 位用户的分数计算排名,不分组,并相应地增加排名。
  2. 基于组的 100 位用户的分数计算排名(每个组的每组结果都应该有自己的排名),并相应地增加排名。

想要的结果是:

+----+------------+----------+------+
| id |    user_id |    score | rank |
+----+------------+----------+------+
|  2 |         29 |       10 |    1 |
|  5 |         32 |        3 |    2 |
|  6 |         33 |        2 |    3 |
|  7 |         34 |        0 |    4 |
|  9 |         39 |        0 |    5 |
| 11 |         41 |        0 |    6 |
| 15 |         47 |        0 |    7 |
| 18 |         51 |        0 |    8 |
+----+------------+----------+------+

基本上用户应该是按分数来排名的,排名应该一直持续到100,即使他们有0。

经过测试的解决方案:

还有更多,但结果是一样的:

+----+------------+----------+------+
| id |    user_id |    score | rank |
+----+------------+----------+------+
|  2 |         29 |       10 |    1 |
|  5 |         32 |        3 |    2 |
|  6 |         33 |        2 |    3 |
|  7 |         34 |        0 |    4 |
|  9 |         39 |        0 |    4 | <-- NOT OK (should be 5)
| 11 |         41 |        0 |    4 | <-- NOT OK (should be 6)
+----+------------+----------+------+

请注意,一些得分为 0 的用户获得了排名……“4”,然后就停止了。我试图解决这个问题很长时间,但没有成功。

甚至还没有正确计算每个组。

使用的最新查询:

SELECT
    T1.id,
    T1.`user_id`,
    T1.`score`,
    T2.rank
    FROM
    `user_scores` T1
    LEFT JOIN (
    SELECT
        `score`,
        (@v_id := @v_Id + 1) AS rank
    FROM
        (
            SELECT DISTINCT
                `score`
            FROM
                `user_scores`
            ORDER BY
                `score` DESC
        ) t,
        (SELECT @v_id := 0) r
    ) T2 ON T1.`score` = T2.`score`   
    ORDER BY
    `score` DESC
    LIMIT 100

我希望我的问题足够清楚,并且有人可以为我提供解决方案/解释。

谢谢

【问题讨论】:

  • @Strawberry 你在说什么?我提供了一切,从表格到查询。
  • 我只能再次向您推荐链接问题中已接受的答案

标签: mysql


【解决方案1】:

试试这个解决方案。

SELECT
    T1.id,
    T1.`user_id`,
    T1.`score`,
    (@v_id := @v_Id + 1) AS rank
    FROM
    `user_scores` T1,
    (SELECT @v_id := 0) r
    LEFT JOIN (
    SELECT
        `score`,
    FROM
        (
            SELECT
                `score`
            FROM
                `user_scores`
            ORDER BY
                `score` DESC
        ) t,
    ) T2 ON T1.`score` = T2.`score`   
    ORDER BY
    `score` DESC
    LIMIT 100

第二种方法:

SET @v_id := 0  //first execute this query

/* then execute this query */
SELECT
T1.id,
T1.`user_id`,
T1.`score`,
(@v_id := @v_Id + 1) AS rank
FROM
`user_scores` T1,
LEFT JOIN (
SELECT
    `score`,
FROM
    (
        SELECT
            `score`
        FROM
            `user_scores`
        ORDER BY
            `score` DESC
    ) t,
) T2 ON T1.`score` = T2.`score`   
ORDER BY
`score` DESC
LIMIT 100

【讨论】:

  • 此 sql 查询未经测试。这只是一个想法。
【解决方案2】:
  1. 根据 100 个用户的分数计算排名,不分组,并相应增加排名
SET @v_id:=0;
SELECT T1.id,
       T1.`user_id`,
       T1.`score`,
       (@v_id := @v_Id + 1) AS rank
FROM `user_scores` T1
ORDER BY `score` DESC
LIMIT 100;
  1. 基于组的 100 位用户的分数计算排名(每个组的每组结果都应该有自己的排名),并相应地增加排名。
SET @v_id:=0;


SET @prev:="";


SELECT id,
       user_id,
       group_id,
       score,
       rank
FROM
  (SELECT T.*,
          @prev AS prev,
          (@v_id := (CASE WHEN(@prev = ""
                               OR @prev = T.`group_id`) THEN @v_id + 1
                         ELSE
                                (SELECT @prev := 1)
                     END)) AS rank, @prev := T.`group_id`
   FROM
     (SELECT T1.id,
             T1.`user_id`,
             T1.`score`,
             T2.`group_id`
      FROM `user_scores` T1
      LEFT JOIN `users` T2 ON T2.`id` = T1.`user_id`
      ORDER BY `group_id` DESC, `score` DESC
      LIMIT 100) T) TT;

对于数字 2,我刚刚保存了之前的 group_id 值并将其与当前的 group_id 进行比较,以便知道何时重置排名。

【讨论】:

  • 有趣,我现在就测试一下。每组怎么样?
  • 我更新了我的要求,因为我不想再忽略那些为 0 的了。
  • @NorbertBoros 你可以在select之外使用SET @v_id:=0;吗?
  • 我可以使用任何东西,只要我得到结果就可以了。我阅读了关于 ROW_NUMBER 的内容,它似乎可以满足我的需要,但需要进行测试。
【解决方案3】:

也许您希望您的查询如下:

SELECT MIN(id) id, user_id, score, rank FROM user_scores GROUP BY rank LIMIT 100

【讨论】:

    猜你喜欢
    • 2021-09-13
    • 1970-01-01
    • 2020-02-28
    • 1970-01-01
    • 2014-04-08
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多