SQL/SQLD

#20 Top-N 쿼리

sundori 2025. 4. 15. 18:02

목차

    정해진 개수의 상위 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