Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a row rank?

Tags:

mysql

rank

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 following table.

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

what I want:

  1. get all the users order by rank. user #1 and #2 should have 1 as their rank value because they both have 30 points

  2. I want to query a rank by user id. I like to get 1 as the result of my rank when I query user #1 and #2 because both of them have 30 points

Added on: 3/18

I tried Logan's query, but got the following result

id point   rank
1   30  1
2   30  1
3   29  3
4   27  5
5   28  4
6   26  6
like image 253
Moon Avatar asked Mar 18 '11 02:03

Moon


3 Answers

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;
like image 195
btilly Avatar answered Oct 07 '22 00:10

btilly


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.

like image 25
RDL Avatar answered Oct 06 '22 22:10

RDL


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.

like image 42
lo5an Avatar answered Oct 07 '22 00:10

lo5an