윈도우 함수(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 값이 같으면 순서 모호
-- 추가 정렬 기준 필요