임에서 점수에 따라 유저의 순위를 구해야 하는 경우가 있다.
ORDER BY로 점수가 높은 순서대로 조회할 수는 있지만 각 유저가 몇 등인지 표시하려면 순위를 계산해야 한다.
이때 사용하는 함수가 ROW_NUMBER, RANK, DENSE_RANK이다.
세 함수는 비슷해 보이지만 같은 점수를 가진 유저를 어떻게 처리하는지가 다르다.
이런 구조의 테이블 이있다고 가정하고 시작하겠다
#PlayerScore
| PlayerId | PlayerName | Score |
|---|---|---|
| 1 | 기사 | 1000 |
| 2 | 마법사 | 900 |
| 3 | 궁수 | 900 |
| 4 | 도적 | 800 |
| 5 | 힐러 | 700 |
SELECT
PlayerId,
PlayerName,
Score,
ROW_NUMBER() OVER (
ORDER BY Score DESC, PlayerId
) AS RowNum,
RANK() OVER (
ORDER BY Score DESC
) AS RankNum,
DENSE_RANK() OVER (
ORDER BY Score DESC
) AS DenseRankNum
FROM #PlayerScore
ORDER BY Score DESC, PlayerId;
이렇게 한번 쿼리를 한번 돌려보면 차이를 한번에 볼수있다
| PlayerName | Score | RowNum | RankNum | DenseRankNum |
|---|---|---|---|---|
| 기사 | 1000 | 1 | 1 | 1 |
| 마법사 | 900 | 2 | 2 | 2 |
| 궁수 | 900 | 3 | 2 | 2 |
| 도적 | 800 | 4 | 4 | 3 |
| 힐러 | 700 | 5 | 5 | 4 |
ROW_NUMBER() 순서대로 번호 부여하고
RANK() 는 동일 순위 그대로 가고 다음 번호는 겹치는게 있으면 생략한다
DENSE_RANK() 는 다음 순위에 겹치더라도 가음 번호 이어서 사용을한다
ROW_NUMBER : 1, 2, 3, 4, 5
RANK : 1, 2, 2, 4, 5
DENSE_RANK : 1, 2, 2, 3, 4
Microsoft 순위 함수 설명
핵심 차이는 다음과 같다. Microsoft 순위 함수 설명에서도 동점 처리에 따라 세 함수를 구분한다.
SELECT
PlayerName,
Score,
ROW_NUMBER() OVER (
ORDER BY Score DESC, PlayerId
) AS RowNum
FROM #PlayerScore
ORDER BY RowNum;
SELECT
PlayerName,
Score,
RANK() OVER (
ORDER BY Score DESC
) AS RankNum
FROM #PlayerScore
ORDER BY Score DESC, PlayerId;
SELECT
PlayerName,
Score,
DENSE_RANK() OVER (
ORDER BY Score DESC
) AS DenseRankNum
FROM #PlayerScore
ORDER BY Score DESC, PlayerId;
ROW_NUMBER() 사용하면서 주의 할것이있는데
ORDER BY Score DESC, PlayerId
ORDER BY Score DESC
으로하면 결과가 다를수도있다 같은 스코어면 누가 우선으로 받는지 보장되지 않는다.
결과 적으로 나는 이걸로 자주 사용할꺼같다
;WITH RankedPlayers AS
(
SELECT
PlayerId,
PlayerName,
Score,
DENSE_RANK() OVER (
ORDER BY Score DESC
) AS RankNum
FROM #PlayerScore
)
SELECT
PlayerName,
Score,
RankNum
FROM RankedPlayers
WHERE RankNum <= 3 -- 순위 3위 이내 유저들 목록 계산
ORDER BY RankNum, PlayerId;