TOP N 쿼리는 정렬된 결과에서 특정 개수(N)의 최상위 행을 추출하는 기법이다. 페이징 처리나 순위 기반 조회 시 효과적으로 사용할 수 있다.
| 방법 | 설명 | 지원 DBMS | 예시 |
|---|---|---|---|
| ROWNUM | 오라클에서 각 행에 번호를 부여하는 가상 컬럼 | Oracle | SELECT * FROM (SELECT * FROM EMP ORDER BY SAL DESC) WHERE ROWNUM <= 5; |
| FETCH | ANSI 표준 SQL:2008부터 도입된 방식 | Oracle 12c 이상, PostgreSQL | SELECT * FROM EMP ORDER BY SAL DESC FETCH FIRST 5 ROWS ONLY; |
| TOP | SQL Server에서 제공하는 TOP N 구문 | SQL Server | SELECT TOP 5 * FROM EMP ORDER BY SAL DESC; |
| LIMIT | MySQL, PostgreSQL 등에서 사용하는 방식 | MySQL, PostgreSQL | SELECT * FROM EMP ORDER BY SAL DESC LIMIT 5; |
ROWNUM은 Oracle에서 제공하는 가상 컬럼으로, 쿼리 결과의 각 행에 1부터 시작하는 번호를 부여한다.
-- 급여가 높은 순서로 상위 5명의 직원 정보 출력 (올바른 방법)
SELECT *
FROM (SELECT EMPNO, ENAME, SAL
FROM EMP
ORDER BY SAL DESC)
WHERE ROWNUM <= 5;
서브쿼리에서 먼저 정렬한 후 바깥 쿼리에서 ROWNUM 조건을 적용한다.
실행 결과실제 급여 상위 5명:
| EMPNO | ENAME | SAL |
|---|---|---|
| 7839 | KING | 5000 |
| 7788 | SCOTT | 3000 |
| 7902 | FORD | 3000 |
| 7566 | JONES | 2975 |
| 7698 | BLAKE | 2850 |
주의사항
- ROWNUM은 WHERE 절에서 행이 선택될 때 할당된다.
- "ROWNUM > n" 조건은 직접 사용할 수 없다(이미 n보다 큰 번호가 할당되지 않았기 때문).
- 정렬된 결과에서 TOP N을 추출하려면 서브쿼리를 사용해야 한다.
-- 급여가 높은 순서로 상위 5명의 직원 정보 출력 (잘못된 방법) SELECT EMPNO, ENAME, SAL, ROWNUM FROM EMP WHERE ROWNUM <= 5 ORDER BY SAL DESC;위 쿼리의 문제점은 먼저 ROWNUM 조건으로 5개 행을 선택한 후 정렬하기 때문에, 실제 급여 상위 5명이 아닌 임의의 5명이 선택된다.
실행 결과임의의 5명이 선택되고 그 중에서 급여 순으로 정렬됨:
EMPNO ENAME SAL ROWNUM 7839 KING 5000 3 7566 JONES 2975 2 7782 CLARK 2450 4 7369 SMITH 800 1 7876 ADAMS 1100 5
특정 범위의 행을 추출할 때(예: 4~6번째 행), 단일 ROWNUM 조건으로는 불가능하다. 이때는 중첩 서브쿼리를 사용한다.
-- 급여가 높은 순서로 4~6번째 직원 정보 출력
SELECT *
FROM (SELECT EMPNO, ENAME, SAL, ROWNUM AS RN
FROM (SELECT EMPNO, ENAME, SAL
FROM EMP
ORDER BY SAL DESC))
WHERE RN BETWEEN 4 AND 6;
급여 순위 4~6위:
| EMPNO | ENAME | SAL | RN |
|---|---|---|---|
| 7566 | JONES | 2975 | 4 |
| 7698 | BLAKE | 2850 | 5 |
| 7782 | CLARK | 2450 | 6 |
Oracle 12c 이상에서는 ANSI 표준 SQL의 FETCH 절을 사용할 수 있다.
-- 급여가 높은 순서로 상위 5명의 직원 정보 출력
SELECT EMPNO, ENAME, SAL
FROM EMP
ORDER BY SAL DESC
FETCH FIRST 5 ROWS ONLY;
실행 결과
급여 상위 5명:
| EMPNO | ENAME | SAL |
|---|---|---|
| 7839 | KING | 5000 |
| 7788 | SCOTT | 3000 |
| 7902 | FORD | 3000 |
| 7566 | JONES | 2975 |
| 7698 | BLAKE | 2850 |
-- OFFSET과 함께 사용하여 페이징 처리
SELECT EMPNO, ENAME, SAL
FROM EMP
ORDER BY SAL DESC
OFFSET 3 ROWS -- 처음 3행 건너뜀
FETCH NEXT 3 ROWS ONLY; -- 다음 3행 추출
실행 결과
급여 순위 4~6위:
| EMPNO | ENAME | SAL |
|---|---|---|
| 7566 | JONES | 2975 |
| 7698 | BLAKE | 2850 |
| 7782 | CLARK | 2450 |
FETCH 절의 장점은 OFFSET과 함께 사용하여 간결하게 페이징 처리를 할 수 있다는 점이다.
SQL Server에서는 TOP 절을 사용하여 쉽게 상위 N개 행을 추출할 수 있다.
-- 급여가 높은 순서로 상위 5명의 직원 정보 출력
SELECT TOP 5 EMPNO, ENAME, SAL
FROM EMP
ORDER BY SAL DESC;
실행 결과
급여 상위 5명:
| EMPNO | ENAME | SAL |
|---|---|---|
| 7839 | KING | 5000 |
| 7788 | SCOTT | 3000 |
| 7902 | FORD | 3000 |
| 7566 | JONES | 2975 |
| 7698 | BLAKE | 2850 |
-- 동일한 값이 있을 경우 함께 반환 (WITH TIES)
SELECT TOP 5 WITH TIES EMPNO, ENAME, SAL
FROM EMP
ORDER BY SAL DESC;
실행 결과
SCOTT와 FORD가 같은 급여로 공동 2위이므로 6명 출력:
| EMPNO | ENAME | SAL |
|---|---|---|
| 7839 | KING | 5000 |
| 7788 | SCOTT | 3000 |
| 7902 | FORD | 3000 |
| 7566 | JONES | 2975 |
| 7698 | BLAKE | 2850 |
| 7782 | CLARK | 2450 |
WITH TIES 옵션을 사용하면 ORDER BY 절에 지정된 컬럼의 값이 같을 경우 모두 함께 반환한다.