2

I saw there are numerous question similar, but I have depleted every solution I found. None of them work as expected for me.

My scenario is as following:

  1. Table with user's score (other data stripped, not relevant):
+--------------+--------------+------+-----+---------+----------------+
| 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. Table with user's (other data stripped, not relevant):
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| group_id        | int(11)      | NO   | MUL | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+
  1. Table with groups (other data stripped, not relevant):
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| name         | varchar(100) | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+

Requirement is:

  1. Calculate rank based on score for 100 users regardless of group, and increment rank accordingly.
  2. Calculate rank based on score for 100 users based on group (each set of result for each group should have it's own rank), and increment rank accordingly.

Desired result is:

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

Basically the users should be ranked by score, and the rank should continue until 100 even if they have 0.

Solutions tested:

And more, but the result is the same:

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

Notice that some users with score 0 get a rank... "4" and it stops there. I tried to fix this quite a long time but no success.

Haven't even got to the point to calculate per group properly.

Latest query used:

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

I hope my question is clear enough and that someone can provide me a solution/explanation.

Thanks

Mecanik
  • 1,539
  • 1
  • 20
  • 50

3 Answers3

0
  1. Calculate rank based on score for 100 users regardless of group, and increment rank accordingly
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. Calculate rank based on score for 100 users based on group (each set of result for each group should have it's own rank), and increment rank accordingly.
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;

For number 2, I just saved the previous group_id value and compare it to the current group_id so I will know when to reset the rank.

Bluetree
  • 1,324
  • 2
  • 8
  • 25
0

Try this solution.

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

Second method:

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
PrakashT
  • 883
  • 1
  • 7
  • 17
-1

Perhaps you want your query like:

SELECT MIN(id) id, user_id, score, rank FROM user_scores GROUP BY rank LIMIT 100
StackSlave
  • 10,613
  • 2
  • 18
  • 35