세인드의 블로그

다른 데이터베이스에서는 ROW_NUMBER()함수나 RANK()함수를 제공하여 별 다른 쿼리문 없이 순위를 구할 수 있지만 MySQL에서는 아쉽게도 저런 유용한 함수들을 제공하지 않습니다.


관련 함수는 없지만 간단한 쿼리를 이용하여 원하는 열을 기준으로 순위를 구하는 기능을 만들었습니다.

SELECT    nick, score, rank FROM (
SELECT    nick,
          score,
          @vRank := @vRank + 1 AS rank
FROM      member AS p, (SELECT @vRank := 0) AS r
ORDER BY  score DESC
) AS CNT WHERE nick = 'a';

이 쿼리는 member 테이블의 nick 열에 있는 'a'의 순위를 반환하는 쿼리입니다.

member 테이블의 모든 요소의 순위를 조회하고 싶으면 첫번째 SELECT FROM문의 서브쿼리인 2~6줄의 쿼리만 실행하시면 됩니다.



쿼리 실행 결과


+------+-------+
| nick | score |
+------+-------+
| a    |     3 |
| b    |     1 |
| c    |     2 |
| d    |     5 |
| e    |     4 |
| f    |     2 |
+------+-------+
+------+-------+------+
| nick | score | rank |
+------+-------+------+
| d    |     5 |    1 |
| e    |     4 |    2 |
| a    |     3 |    3 |
| c    |     2 |    4 |
| f    |     2 |    5 |
| b    |     1 |    6 |
+------+-------+------+
실행 전실행 후

이 쿼리문은 점수가 동점인 경우 각각 다른 순위를 부여합니다. 실행 후 테이블의 7, 8 라인을 보면 c, f 열의 점수가 각각 2점으로 동점이지만 rank는 4와 5가 부여된 것을 볼 수 있습니다. 만약 동점자를 같은 순위로 처리하려고 한다면 아래의 쿼리를 참고하시면 됩니다.



동점자를 같은 순위로 처리하기


SELECT    nick, score, rank FROM (
SELECT    nick,
          score,
          CASE
          WHEN @prev_value = score THEN @vRank
          WHEN @prev_value := score THEN @vRank := @vRank + 1
          END AS rank
FROM      member AS p, (SELECT @vRank := 0, @prev_value := NULL) AS r
ORDER BY  score DESC
) AS CNT WHERE nick = 'a';

아래는 2~9라인의 쿼리 실행 결과입니다.

+------+-------+------+
| nick | score | rank |
+------+-------+------+
| d    |     5 |    1 |
| e    |     4 |    2 |
| a    |     3 |    3 |
| c    |     2 |    4 |
| f    |     2 |    4 |
| b    |     1 |    5 |
+------+-------+------+

점수가 2점인 유저에 대해서 각각 4위의 순위가 부여된 것을 확인할 수 있습니다.