본문 바로가기

SQL/내용 정리

Window Function - 순위 매기기(RANK() OVER), 반환 행 수 제한하기(LIMIT)

윈도우 함수(Window Function)
  • 그룹은 유지하면서, 각 행에 계산 결과를 덧붙이는 함수
  • == 특정 기준으로 “창(window)”을 만들고 그 범위 내에서 계산한 결과를 각 행에 반환하는 함수
  • → 엑셀에서 원본 행은 그대로 두고, 옆 열에 순위/합계/비율을 추가하는 느낌
  • 왜 필요한가?
    • 아래와 같은 문제를 쉽게 해결(예시) :
      • 음식 타입별로 상위 3개 식당
      • 각 식당이 카테고리 내에서 차지하는 비율
      • 누적합(러닝 합계) 계산
      • 사용자별 첫 주문 / 두 번째 주문 비교
    • 기존 SQL로는 서브쿼리/조인 반복이 필요하지만, Window Function으로 한 번에 계산 가능
  • 순서 : PARTITION BY로 나누고 → ORDER BY로 정렬 → 함수 적용
-- 기본 구조

window_function(argument)
OVER (
    PARTITION BY 그룹기준
    ORDER BY 정렬기준
)

 

GROUP BY vs Window Function 차이
구분 GROUP BY Window
결과 행이 줄어듦 행 유지
목적 집계 계산 + 유지
ex. 평균 순위, 누적합

 

 


 

RANK() OVER
  • 정렬 기준에 따라 각 행에 순위(rank)를 부여
    • 같은 값이 있으면 같은 순위를 주고, 그 다음 순위는 건너뜀
    • GROUP BY처럼 행을 합쳐버리는 게 아니라, 원래 행을 유지한 채 계산 결과만 추가
-- 기본 문법

RANK() OVER (ORDER BY column DESC)
-- 예시

SELECT
    id,
    `name`,
    region,
    RANK() OVER(ORDER BY rating DESC) AS top_rank,  -- rating 높은 순으로 순위 부여, 동점이면 같은 순위
    join_date
FROM
    lol_users;
-- 실습.

-- Step 1. 집계

SELECT
    cuisine_type,
    restaurant_name,
    COUNT(1) order_count
FROM
    food_orders
GROUP BY
    1, 2;
    
    
-- Step 2. Rank 적용

SELECT
    cuisine_type,
    restaurant_name,
    RANK() OVER (
        PARTITION BY cuisine_type
        ORDER BY order_count DESC
    ) rn,
    order_count
FROM
    (
    SELECT
        cuisine_type,
        restaurant_name,
        COUNT(1) order_count
    FROM
        food_orders
    GROUP BY
        1, 2
    ) a;
    

-- Step 3. 상위 3개 조회

SELECT
    cuisine_type,
    restaurant_name,
    order_count,
    rn "순위"
FROM
    (
    SELECT
        cuisine_type,
        restaurant_name,
        RANK() OVER (
            PARTITION BY cuisine_type
            ORDER BY order_count DESC
        ) rn,
        order_count
    FROM
        (
        SELECT
            cuisine_type,
            restaurant_name,
            COUNT(1) order_count
        FROM
            food_orders
        GROUP BY
            1, 2
        ) a
    ) b
WHERE
    rn <= 3
ORDER BY
    1, 4;
  
  
/*
주요 내용
- PARTITION BY → 음식 타입별로 그룹 나눔
- ORDER BY → 주문수 기준 정렬
- RANK → 순위 생성
*/

 

 


 

LIMIT
  • SELECT 결과 중에서 반환할 행 수를 제한하는 절
    • ex. 조회 결과가 100개여도 LIMIT 10을 쓰면 10개만 가져옴
  • 주의할 점
    • ORDER BY와 같이 쓰는 게 중요(정렬 기준이 없으면 애매함)
      • ex. 최신 1명, 점수 상위 3명, 가장 오래된 날짜 10건...
-- 기본 문법(10개 제한일 경우)

SELECT ...
FROM ...
LIMIT 10;
-- 예시

SELECT
    `name`
FROM
    lol_users
ORDER BY
    join_date DESC   -- join_date 최신순 정렬
LIMIT 1;             -- 가장 위 1행만 반환

 

 


 

Sum(비율 + 누적합)
-- 실습.

-- Step 1. 집계

SELECT
    cuisine_type,
    restaurant_name,
    COUNT(1) cnt_order
FROM
    food_orders
GROUP BY
    1, 2;
    

-- Step 2. 합계 + 누적합

SELECT
    cuisine_type,
    restaurant_name,
    cnt_order,
    SUM(cnt_order) OVER (
        PARTITION BY cuisine_type
    ) sum_cuisine,   -- 전체 합
    SUM(cnt_order) OVER (
        PARTITION BY cuisine_type
        ORDER BY cnt_order
    ) cum_cuisine    -- 누적합
FROM
    (
    SELECT
        cuisine_type,
        restaurant_name,
        COUNT(1) cnt_order
    FROM
        food_orders
    GROUP BY
        1, 2
    ) a
ORDER BY
    cuisine_type,
    cnt_order;
    
    
-- 누적합 오류 해결

SUM(cnt_order) OVER (
    PARTITION BY cuisine_type
    ORDER BY cnt_order, restaurant_name
)

-- cnt_order 값이 같으면 순서 모호
-- 추가 정렬 기준 필요