437. 순위 함수 (RANK vs DENSE_RANK)
⚠️ 이 문서는 윈도우 함수(436번 문서) 중에서도 게시판의 베스트 글 순위나, 전교 1등부터 100등까지의 성적을 매길 때 필수적으로 사용하는 '순위(Ranking)' 함수들과 그들 간의 미묘하고도 중요한 동점자 처리 방식의 차이점을 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질:
ORDER BY로 줄을 세운 뒤, 1번부터 차례대로 등수(1, 2, 3...)를 매겨주는 함수다. 무조건OVER()절과 함께 써야 한다.- RANK(): 동점자가 나오면 똑같은 등수를 주고, 그 동점자 수만큼 다음 등수를 훌쩍 뛰어넘는(건너뛰는) 함수다. (예: 1등, 2등, 2등, 4등)
- DENSE_RANK(): 동점자가 나와도 다음 등수를 건너뛰지 않고 빽빽하게(Dense) 등수를 이어가는 함수다. (예: 1등, 2등, 2등, 3등)
Ⅰ. 개요: 공동 2등 다음은 몇 등일까? (Context & Necessity)
"우리 반 학생들의 수학 점수 순위를 매겨줘!" 선생님의 지시에 따라 점수대로 학생들을 세웠다.
- 김철수: 100점
- 이영희: 90점
- 박민수: 90점
- 최보스: 80점
문제는 영희와 민수가 동점이라는 것이다. 이 둘을 '공동 2등'으로 처리하는 것까진 좋은데, 그다음 80점인 최보스를 3등으로 불러야 할까, 아니면 4등으로 불러야 할까? 데이터베이스는 이 고민을 덜어주기 위해, 두 가지 상황에 맞춰 골라 쓸 수 있는 서로 다른 2개의 함수를 제공한다.
📢 섹션 요약 비유:
RANK()는 올림픽 메달 수여식과 같습니다. 공동 은메달이 2명 나오면 동메달은 아무에게도 주지 않죠 (1등, 2등, 2등, 4등). 반면DENSE_RANK()는 게임의 '티어(Tier)'와 같습니다. 브론즈, 실버, 골드처럼 사람이 몇 명이든 중간에 비는 등급(등수) 없이 빽빽하게 채워줍니다.
Ⅱ. 3가지 순위 함수의 완벽 비교 ★
시험에서 점수표를 던져주고 "결과값이 다른 하나는?"이라는 형태로 무조건 출제되는 3형제다.
1. RANK() - 동점자 점프 O
- 동점자에게 같은 등수를 준다.
- 그다음 등수는 동점자 수만큼 건너뛴다.
- 결과:
1, 2, 2, 4, 5...
2. DENSE_RANK() - 동점자 점프 X
- 동점자에게 같은 등수를 준다.
- 그다음 등수는 무조건 바로 다음 숫자(연속된 숫자)를 준다.
- 결과:
1, 2, 2, 3, 4...
3. ROW_NUMBER() - 무자비한 일련번호
- 동점이고 나발이고 신경 안 쓴다.
- 무조건 1부터 시작해서 1, 2, 3, 4 고유한 일련번호를 억지로 부여한다. (동점자는 내부적인 랜덤 순서나 다른 기준에 의해 줄이 세워짐)
- 결과:
1, 2, 3, 4, 5... - 페이징 처리(게시판 1페이지에 10개씩 보여주기)를 할 때 압도적으로 많이 쓰인다.
Ⅲ. 실무 쿼리 예시
"부서별(PARTITION BY)로 월급 순위(ORDER BY)를 매겨줘!"
SELECT 이름, 부서, 월급,
RANK() OVER (PARTITION BY 부서 ORDER BY 월급 DESC) AS 일반순위,
DENSE_RANK() OVER (PARTITION BY 부서 ORDER BY 월급 DESC) AS 빽빽한순위,
ROW_NUMBER() OVER (PARTITION BY 부서 ORDER BY 월급 DESC) AS 그냥번호
FROM 직원;
┌──────────────────────────────────────────────────────────────┐
│ 3가지 순위 함수의 동점자 처리 결과 시각화 │
├──────────────────────────────────────────────────────────────┤
│ │
│ 이름 │ 월급 │ RANK() │ DENSE_RANK() │ ROW_NUMBER() │
│ ────┼──────┼────────┼──────────────┼────────────── │
│ 철수 │ 500 │ 1 │ 1 │ 1 │
│ 영희 │ 400 │ 2 🌟 │ 2 🌟 │ 2 │
│ 민수 │ 400 │ 2 🌟 │ 2 🌟 │ 3 (동점 무시) │
│ 동건 │ 300 │ 4 💥 │ 3 🛡️ │ 4 │
│ 진우 │ 200 │ 5 │ 4 │ 5 │
│ │
│ ★ 특징: 400점으로 동점인 영희와 민수 다음 사람(동건)의 등수를 보라! │
│ RANK()는 3등을 빼먹었고, DENSE_RANK()는 3등으로 꽉 채웠다. │
└──────────────────────────────────────────────────────────────┘
Ⅳ. 결론
"1등을 찾는 것보다, 2등을 어떻게 대우할 것인가가 더 어렵다."
순위 함수는 윈도우 함수의 가장 대표적인 활용 사례다. 특히 서브쿼리와 묶어서 "부서별로 월급이 가장 높은 사람 3명씩만 뽑아와(WHERE rank <= 3)" 같은 Top-N 쿼리를 짤 때 이 함수들의 가치는 빛을 발한다. 비즈니스 요구사항에 따라 "공동 우승자가 3명이면 4등에게 상금을 줄 것인가(RANK), 아니면 2등 상금을 줄 것인가(DENSE_RANK)?"를 고민하여 적절한 함수를 꺼내 드는 것이 백엔드 엔지니어의 디테일이다.
📌 관련 개념 맵
- 기반 문법: Window Function
OVER()절 (436번 문서) - Top-N 쿼리:
ORDER BY ... LIMIT 3(MySQL),FETCH FIRST 3 ROWS ONLY(Oracle) - 보조 키워드:
PARTITION BY(그룹별 순위를 매길 때 사용)
👶 어린이를 위한 3줄 비유 설명
- 달리기 시합에서 찰리와 스누피가 똑같이 10초에 들어와서 '공동 2등'이 됐어요.
RANK심판은 "너희 둘이 2등, 3등 자리를 다 차지했으니까 다음으로 들어온 우드스탁은 4등이야!"라고 해요.DENSE_RANK심판은 "너희 둘이 공동 2등이니까, 3등 상장이 아직 남았네? 다음으로 들어온 우드스탁이 3등이야!"라고 빽빽하게 상장을 나눠준답니다!