목차
정해진 개수의 상위 N개 행만 조회하는 쿼리로, 실무에서 매우 자주 사용이 된다. (예: 상위 5위, 최신 10건, 점수 Top 3 등).
Top-N 쿼리
Top-N 쿼리는 정렬된 결과 중 일정 개수(N개)만 추출하고 싶을 때 사용한다.
DBMS마다 문법 차이는 있지만, 정렬 + 제한이라는 구조는 동일하다.
-- 예제 쿼리 MySQL / PostgreSQL
SELECT name, score
FROM students
ORDER BY score DESC
LIMIT 3;
-- Oracle 구버전
SELECT name, score
FROM (
SELECT name, score
FROM students
ORDER BY score DESC
)
WHERE ROWNUM <= 3;
-- Oracle 12c 이상
SELECT name, score
FROM students
ORDER BY score DESC
FETCH FIRST 3 ROWS ONLY;
--SQL Serve(MSSQL)
SELECT TOP 3 name, score
FROM students
ORDER BY score DESC;
-- 윈도우 함수로 구현(RANK 기반 Top-N)
SELECT *
FROM (
SELECT name, score,
RANK() OVER (ORDER BY score DESC) AS rnk
FROM students
) t
WHERE rnk <= 3;
--
name | score
------+-------
철수 | 95
영희 | 92
지수 | 90
✅ 기타 DBMS별 방식
DBMS | 사용 문법 예시 |
MySQL | LIMIT n |
PostgreSQL | LIMIT n |
Oracle 12c+ | FETCH FIRST n ROWS ONLY |
Oracle (구버전) | WHERE ROWNUM <= n |
SQL Server | TOP n 사용 |
students 테이블 | ||
id | name | score |
1 | 철수 | 85 |
2 | 영희 | 90 |
3 | 민수 | 92 |
4 | 지수 | 95 |
5 | 나리 | 100 |
ROWNUM을 이용한 Top-N 쿼리 (Oracle 구버전)
ROWNUM은 가상으로 붙는 행 번호이며, 서브쿼리로 정렬 후 감싸야 정확한 순번이 보장이 된다.
SELECT *
FROM (
SELECT name, score
FROM students
ORDER BY score DESC
)
WHERE ROWNUM <= 3;
--
name | score
------+-------
철수 | 95
영희 | 92
지수 | 90
- ORDER BY된 결과 중 상위 3개를 ROWNUM으로 걸러냄.
ROW_NUMBER()를 이용한 Top-N 쿼리 (윈도우 함수)
ROW_NUMBER()는 모든 행에 고유한 순서를 부여하므로 Top-N에 적합하다고 할 수 있다.. 동점자 없이 정확히 N개만 나옴.
SELECT *
FROM (
SELECT name, score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS rn
FROM students
) t
WHERE rn <= 3;
--
name | score | rn
------+-------+----
철수 | 95 | 1
영희 | 92 | 2
지수 | 90 | 3
- 점수 내림차순 기준으로 각 행에 고유한 순위 번호 부여 후, 상위 3개만 선택.
RANK()를 이용한 Top-N 쿼리
RANK()는 동점자에게 동일 순위 부여, 다음 순위는 건너뜀
→ 3등이 2명이면 다음 순위는 5등이 됨.
→ 동점자 포함 Top-N 조회에 유리
SELECT *
FROM (
SELECT name, score,
RANK() OVER (ORDER BY score DESC) AS rnk
FROM students
) t
WHERE rnk <= 3;
--
name | score | rnk
------+-------+----
철수 | 95 | 1
영희 | 92 | 2
지수 | 92 | 2
동점자 포함해서 3등까지 포함한 모든 행을 가져온다
Top-N에 동점자까지 포함시키고 싶을 때 딱이다
DENSE_RANK()를 이용한 Top-N 쿼리
DENSE_RANK()도 동점자 동일 순위 부여
차이점은 순위를 건너뛰지 않고 연속적으로 부여됨
→ 3등이 2명이면 다음은 4등 (X), 3등, 3등, 4등
SELECT *
FROM (
SELECT name, score,
DENSE_RANK() OVER (ORDER BY score DESC) AS drnk
FROM students
) t
WHERE drnk <= 3;
--
name | score | drnk
------+-------+-----
철수 | 95 | 1
영희 | 92 | 2
지수 | 92 | 2
민수 | 85 | 3
순위가 건너뛰지 않고 매겨지므로, 정확히 N개의 순위를 포함하는 데에 적합
✅ 최종 비교 요약표
방식 | 동점 처리 | 순위 건너뜀 | 정확히 N개? | 동점 포함 Top-N? | 특징 |
ROWNUM | ❌ 무시됨 | ❌ 없음 | ✅ 가능 | ❌ 동점 X | Oracle 구버전 전용 |
ROW_NUMBER | ❌ 무시됨 | ❌ 없음 | ✅ 가능 | ❌ 동점 X | 고유 순번 보장 |
RANK | ✅ 동점 같음 | ✅ O | ❌ 초과될 수 있음 | ✅ O | 건너뛰는 순위 |
DENSE_RANK | ✅ 동점 같음 | ❌ 없음 | ❌ 초과될 수 있음 | ✅ O | 연속된 순위 |
언제 무엇을 써야할가? | |
상황 | 추천 방식 |
동점자 무시하고 정확히 3개만 뽑기 | ROW_NUMBER() |
3등까지 모두 포함 (동점자도 포함) | RANK() |
순위가 연속되도록 (건너뛰지 않게) | DENSE_RANK() |
Oracle 구버전이라면 | ROWNUM |
728x90
'SQL > SQLD' 카테고리의 다른 글
#23 DML (0) | 2025.04.15 |
---|---|
#22 계층 쿼리 (0) | 2025.04.15 |
#19 윈도우 함수 (0) | 2025.04.15 |
#18 그룹 함수 (0) | 2025.04.14 |
#17 집합 연산자 (0) | 2025.04.14 |