How to get a row rank?

后端 未结 6 1924
一生所求
一生所求 2021-01-05 04:08

HI,

I actually posted similar (or same?) question yesterday, but I thought I need to post a new question since I have short, but clear question.

I have the f

相关标签:
6条回答
  • 2021-01-05 04:25

    Just count how many people have more points then them.

    select count(1) from users 
    where point > (select point from users where id = 2) group by point
    

    This will give you the number of people that have more points for the given user. So for user 1 and user 2 the result will be 0 (zero) meaning they are first.

    0 讨论(0)
  • 2021-01-05 04:33

    The subquery approach that you have seen recommended will scale quadratically. http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/ shows a much more efficient approach with user variables. Here is an untested adaptation to your problem:

    @points := -1; // Should be an impossible value.
    @num := 0;
    
    SELECT id
      , points
      , @num := if(@points = points, @num, @num + 1) as point_rank
      , @points := points as dummy
    FROM `users`
    ORDER BY points desc, id asc;
    
    0 讨论(0)
  • 2021-01-05 04:33

    In mysql 8 you can use window function like:

    SELECT
      id,
      score,
      rank() over (order by amount) as ranking
    FROM
      SomeTable
    

    If you need to select only one row, use a subquery:

    SELECT
      id
      score,
      ranking
    FROM (
      SELECT
        id,
        score,
        rank() over (order by score) as ranking
      FROM
        SomeTable
    ) t
    WHERE
      id = ?
    
    0 讨论(0)
  • 2021-01-05 04:34
    SET @rank = 0, @prev_val = NULL;
    SELECT id, @rank := IF(@prev_val=points,@rank,@rank+1) AS rank,
    @prev_val := points AS points FROM users ORDER BY points DESC, id asc;
    

    Table:users

    0 讨论(0)
  • 2021-01-05 04:41

    The OP would like to have rank numbers skipped if their previously were duplicate points with the same rank. E.g. below see how 2 is skipped because rank 1 appears twice.

    id  point  rank
    1   30     1
    2   30     1
    3   29     3
    4   27     4
    5   28     5
    6   26     6
    

    This can be achieved by modifying btilly's code as follows:

    set @points := -1; // Should be an impossible value.
    set @num := 0;
    set @c := 1;
    SELECT id
      , points
      , @num := if(@points = points, @num, @num + @c) as point_rank
      , @c := if(@points = points, @c+1, 1) as dummy
      , @points := points as dummy2
    FROM `users`
    ORDER BY points desc, id asc;
    
    0 讨论(0)
  • 2021-01-05 04:49

    When I needed to do something similar, I created a view that looked like this:

    CREATE VIEW rankings_view 
    AS 
    SELECT id
    ,      point
    ,      (select count(1) 
              from points b
             where  b.point > a.point) +1 as rank
    FROM points as a;
    

    This assumes that the original table was named points, obviously. Then you can get the rank of any id, or the id corresponding to any rank, by querying the view.

    EDIT

    If you want to count the number of distinct point values above each point value instead of the number of entries with point values above the current point value, you can do something like:

    CREATE VIEW rankings_view2
    AS 
    SELECT id
    ,      point
    ,      (SELECT COUNT(1) +1 AS rank 
              FROM ( SELECT DISTINCT point
                       FROM points b
                      WHERE   b.point >a.point ))
    FROM points AS a;
    

    NOTE

    Some of the other solutions presented definitely perform better than this one. They're mysql specific, so I can't really use them for what I'm doing. My application has, at most, 128 entities to rank, so this works well enough for me. If you might have tons of rows, though, you might want to look at using one of the other solutions presented here or limiting the scope of the ranking.

    0 讨论(0)
提交回复
热议问题