분석을 위한 기본 윈도우 함수들
시작하기 전에, 네가 수천 개의 판매 행이 있는 테이블로 일한다고 상상해봐. 네 임무는 각 카테고리에서 누가 1등 판매자인지, 누가 2등인지, 이런 식으로 순위를 정하는 거야. 아니면, 그냥 모든 행에 번호를 붙여서 순서를 추적해야 할 수도 있지. 이런 거, 윈도우 함수로 아주 쉽게 할 수 있어.
윈도우 함수는 SQL에서 데이터셋의 일부 행(이걸 "윈도우"라고 부를게)에서 동작하는 함수야. 집계 함수(예를 들어 SUM()이나 AVG())는 여러 행을 하나로 합치지만, 윈도우 함수는 원래 행을 그대로 두고 계산된 값을 추가해줘.
집계 함수와의 차이점
집계 함수는 데이터를 "압축"해서 행을 그룹으로 묶어:
SELECT department, COUNT(*)
FROM employees
GROUP BY department;
결과: 부서 수만큼 몇 개의 행만 나와.
윈도우 함수랑 비교해보면 — 여기서는 행이 그대로 남고, 예를 들어 ROW_NUMBER() 같은 새로운 필드가 추가돼:
SELECT employee_name, department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_within_department
FROM employees;
여기서는 모든 행이 다 나오고, rank_within_department라는 컬럼이 추가돼서 각 직원이 자기 부서에서 몇 번째인지 번호가 붙어 있어.
기본 윈도우 함수들
OVER() 문법
모든 윈도우 함수에서 제일 중요한 부분이 바로 OVER()라는 마법 같은 단어야. 이게 함수가 어떤 "윈도우"에서 동작할지 정해줘. OVER() 안에는 그룹 나누기(PARTITION BY)랑 정렬 순서(ORDER BY)를 지정할 수 있어.
기본 문법:
<윈도우_함수>() OVER (
[PARTITION BY <그룹>]
[ORDER BY <순서>]
)
구성 요소:
PARTITION BY: 행을 그룹으로 나눠. 예를 들어, "부서별로 데이터를 나눠줘."ORDER BY: 행을 어떤 순서로 처리할지 정해. 예를 들어, "직원들을 급여 내림차순으로 정렬해줘."
ROW_NUMBER() 함수
ROW_NUMBER() 함수는 지정한 "윈도우" 안에서 1부터 행에 번호를 붙여줘. 임시 테이블에서 행 번호를 만들거나, 레코드의 순서를 정할 때 유용해.
예시. sales (판매) 테이블:
| id | product_category | seller_name | revenue |
|---|---|---|---|
| 1 | Electronics | Alice | 1000 |
| 2 | Electronics | Bob | 850 |
| 3 | Furniture | Alice | 1200 |
| 4 | Furniture | Charlie | 1100 |
| 5 | Electronics | Dana | 750 |
쿼리:
SELECT seller_name, product_category, revenue,
ROW_NUMBER() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS row_number
FROM sales;
결과:
| seller_name | product_category | revenue | row_number |
|---|---|---|---|
| Alice | Electronics | 1000 | 1 |
| Bob | Electronics | 850 | 2 |
| Dana | Electronics | 750 | 3 |
| Alice | Furniture | 1200 | 1 |
| Charlie | Furniture | 1100 | 2 |
작동 방식:
- 데이터가
product_category별로 그룹으로 나뉘어. - 각 그룹은
revenue기준(내림차순)으로 정렬돼. - 각 그룹 안에서 행에 순서대로 번호가 붙어.
RANK() 함수
RANK() 함수는 행을 랭킹할 때 써. ROW_NUMBER()와 다르게, 동일한 값이 있으면 같은 순위를 주고, 그만큼 순위(랭크) 번호를 건너뛰어.
예시:
SELECT seller_name, product_category, revenue,
RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS rank
FROM sales;
결과:
| seller_name | product_category | revenue | rank |
|---|---|---|---|
| Alice | Electronics | 1000 | 1 |
| Bob | Electronics | 850 | 2 |
| Dana | Electronics | 750 | 3 |
| Alice | Furniture | 1200 | 1 |
| Charlie | Furniture | 1100 | 2 |
DENSE_RANK() 함수
DENSE_RANK()는 RANK()랑 비슷한데, 한 가지 차이점이 있어: 동일한 값이 있어도 랭크 번호를 건너뛰지 않아.
예시. 같은 매출이 있는 판매를 추가해보자:
| id | product_category | seller_name | revenue |
|---|---|---|---|
| 6 | Electronics | Alice | 1000 |
| 7 | Electronics | Dana | 750 |
쿼리:
SELECT seller_name, product_category, revenue,
DENSE_RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS dense_rank
FROM sales;
결과:
| seller_name | product_category | revenue | dense_rank |
|---|---|---|---|
| Alice | Electronics | 1000 | 1 |
| Alice | Electronics | 1000 | 1 |
| Bob | Electronics | 850 | 2 |
| Dana | Electronics | 750 | 3 |
사용 예시: 행 번호 붙이기
문제: orders 테이블에서 주문을 날짜순으로 정렬해서 모두 번호를 붙여야 해.
SELECT order_id, customer_name, order_date,
ROW_NUMBER() OVER (ORDER BY order_date) AS order_number
FROM orders;
결과: 주문이 처리된 순서대로 번호가 붙은 리스트를 얻을 수 있어.
사용 예시: 각 카테고리별 TOP 3 판매자
문제: 각 상품 카테고리에서 상위 3명의 판매자를 뽑아야 해.
WITH ranked_sales AS (
SELECT seller_name, product_category, revenue,
RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS rank
FROM sales
)
SELECT seller_name, product_category, revenue
FROM ranked_sales
WHERE rank <= 3;
사용 예시: 동일한 매출 찾기
문제: 각 카테고리에서 매출이 같은 판매자가 있는지 확인해야 해.
SELECT seller_name, product_category, revenue,
DENSE_RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS dense_rank
FROM sales;
이제 "겹치는" 값이 어디에 있는지 랭크로 바로 볼 수 있어.
GO TO FULL VERSION