GROUP BY를 사용하면 데이터가 그룹별로 묶이면서 개별 행이 사라지지만, 윈도우 함수는 개별 행을 유지한 채 연산을 수행합니다.
✅ OVER() 절을 사용하여 그룹을 정의
OVER(PARTITION BY column ORDER BY column) 형식으로 윈도우(창, 그룹) 를 지정합니다.
PARTITION BY는 그룹화 기준을 정의하고, ORDER BY는 정렬 순서를 지정합니다.
✅ 대표적인 활용 예시
순위 매기기 (RANK, DENSE_RANK, ROW_NUMBER)
누적 합계, 누적 비율 (SUM, AVG, CUME_DIST)
이전/다음 행 참조 (LAG, LEAD)
📊 2. 윈도우 함수 vs 그룹 함수 차이점
기능
윈도우 함수
그룹 함수 (GROUP BY)
데이터 유지
개별 행 유지
개별 행이 제거됨
연산 적용 방식
각 행에 대해 적용
그룹 전체에 대해 하나의 값 반환
대표적인 함수
ROW_NUMBER, RANK, CUME_DIST, NTILE, SUM() OVER()
SUM(), AVG(), COUNT()
예제
SUM(salary) OVER (PARTITION BY department_id)
SUM(salary) GROUP BY department_id
🛠 3. 윈도우 함수의 기본 구조
윈도우 함수() OVER ( PARTITION BY 그룹화 기준 ORDER BY 정렬 기준 )
✅ PARTITION BY (선택 사항)
그룹을 나누는 기준 (부서별, 지역별 등)
생략하면 전체 데이터를 하나의 그룹으로 간주
✅ ORDER BY (선택 사항)
계산 순서를 지정 (급여 순, 날짜 순 등)
🔍 4. 대표적인 윈도우 함수 종류
📌 (1) 순위 관련 함수
함수
설명
반환 값
ROW_NUMBER()
각 행에 고유한 순위를 부여
1, 2, 3, …
RANK()
동일 값에는 같은 순위, 이후 순위 건너뜀
1, 2, 2, 4, …
DENSE_RANK()
동일 값에는 같은 순위, 이후 순위 건너뛰지 않음
1, 2, 2, 3, …
NTILE(n)
데이터를 n개 그룹으로 나눔
1 ~ n
📌 예제
SELECT employee_id, department_id, salary, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS row_num, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank, DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dense_rank, NTILE(4) OVER (PARTITION BY department_id ORDER BY salary DESC) AS quartile FROM employees;
📌 (2) 집계 함수
함수
설명
SUM()
그룹 내 누적 합계
AVG()
그룹 내 평균 값
COUNT()
그룹 내 행 개수
MIN()
그룹 내 최소값
MAX()
그룹 내 최대값
📌 예제
SELECT employee_id, department_id, salary, SUM(salary) OVER (PARTITION BY department_id) AS total_salary, AVG(salary) OVER (PARTITION BY department_id) AS avg_salary FROM employees;
📌 (3) 누적 비율 함수
함수
설명
CUME_DIST()
누적 분포 계산
PERCENT_RANK()
백분율 순위 계산
RATIO_TO_REPORT()
그룹 내 전체 합 대비 개별 비율
📌 예제
SELECT employee_id, department_id, salary, CUME_DIST() OVER (PARTITION BY department_id ORDER BY salary DESC) AS cum_dist, RATIO_TO_REPORT(salary) OVER (PARTITION BY department_id) AS salary_ratio FROM employees;
📌 (4) 이전/다음 행 참조 함수
함수
설명
LAG()
이전 행의 값 가져오기
LEAD()
다음 행의 값 가져오기
FIRST_VALUE()
그룹 내 첫 번째 값 반환
LAST_VALUE()
그룹 내 마지막 값 반환
NTH_VALUE(n)
그룹 내 n번째 값 반환
📌 예제
SELECT employee_id, department_id, salary, LAG(salary) OVER (PARTITION BY department_id ORDER BY salary DESC) AS prev_salary, LEAD(salary) OVER (PARTITION BY department_id ORDER BY salary DESC) AS next_salary, FIRST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary DESC) AS first_salary FROM employees;
📝 5. 정리
함수 유형
주요 함수
설명
순위 함수
ROW_NUMBER, RANK, DENSE_RANK, NTILE
행별 순위 계산
집계 함수
SUM, AVG, COUNT, MIN, MAX
그룹 내 합계, 평균 계산
비율 함수
CUME_DIST, PERCENT_RANK, RATIO_TO_REPORT
누적 비율, 백분율 순위
이전/다음 행 함수
LAG, LEAD, FIRST_VALUE, LAST_VALUE
이전/다음 행 참조
🚀 6. 윈도우 함수 활용 예시
✅ 1) 부서별 급여 합산하면서 개별 급여도 유지
SELECT employee_id, department_id, salary, SUM(salary) OVER (PARTITION BY department_id) AS total_salary FROM employees;
✔️ 개별 급여를 유지한 채 부서별 총 급여를 표시
✅ 2) 상위 20% 급여자 조회 (CUME_DIST)
SELECT * FROM ( SELECT employee_id, salary, CUME_DIST() OVER (ORDER BY salary DESC) AS cum_dist FROM employees ) subquery WHERE cum_dist <= 0.2;
✔️ 급여 기준 상위 20% 직원 조회
✅ 3) 직원 성과 평가 그룹 나누기 (NTILE)
SELECT employee_id, performance_score, NTILE(3) OVER (ORDER BY performance_score DESC) AS perf_group FROM employees;
✔️ 직원들을 3개의 성과 그룹으로 분류
🎯 7. 결론
윈도우 함수는 개별 행을 유지하면서 연산을 수행하는 강력한 SQL 기능
PARTITION BY를 사용하여 그룹화, ORDER BY로 정렬 기준 지정
순위 계산, 누적 합계, 이전/다음 행 참조 등 다양한 활용 가능
데이터 분석, 보고서 작성, 성과 평가 등에서 필수적인 기능
윈도우 함수 13개 상세 정리
함수명
설명
반환 값
PARTITION BY 사용 가능
ORDER BY 필수 여부
ROW_NUMBER()
정렬된 행에 대해 순차적인 번호를 부여
1, 2, 3, …
O
O
RANK()
동일한 값에 동일한 순위, 이후 순위 건너뜀
1, 2, 2, 4, …
O
O
DENSE_RANK()
동일한 값에 동일한 순위, 이후 순위 건너뛰지 않음
1, 2, 2, 3, …
O
O
PERCENT_RANK()
(RANK – 1) / (전체 행 수 – 1)로 백분율 순위
0.0 ~ 1.0
O
O
LAG()
이전 행의 값 가져오기
이전 행 값 또는 NULL
O
X
LEAD()
다음 행의 값 가져오기
다음 행 값 또는 NULL
O
X
FIRST_VALUE()
파티션 내 첫 번째 값 반환
첫 번째 값
O
O
LAST_VALUE()
파티션 내 마지막 값 반환
마지막 값
O
O
NTH_VALUE()
특정 번째(n) 값 반환
n번째 값
O
O
MEDIAN()
중간 값 반환 (일부 DBMS에서 지원)
중간값
O
O
함수명
설명
반환 값
PARTITION BY 사용 여부
ORDER BY 필수 여부
주요 활용
CUME_DIST()
특정 값이 그룹 내에서 차지하는 누적 비율
0 < 값 ≤ 1.0
O
O
누적 분포 계산
RATIO_TO_REPORT()
특정 값이 전체 합계에서 차지하는 비율
0 ≤ 값 ≤ 1.0
O
X
전체 대비 특정 행 비율 계산
NTILE(n)
데이터를 n개의 그룹으로 나누어 그룹 번호를 반환
1 ~ n 값
O
O
데이터 그룹화
1. ROW_NUMBER()
설명
각 행에 고유한 번호를 부여 (ORDER BY 기준)
중복값이 있어도 순차적인 번호를 부여함
SQL 예제
SELECT employee_id, department_id, salary, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS row_num FROM employees;
결과
employee_id
department_id
salary
row_num
101
10
9000
1
102
10
7000
2
103
10
6000
3
2. RANK()
설명
동일한 값이면 같은 순위를 부여, 이후 순위 건너뜀
SQL 예제
SELECT employee_id, department_id, salary, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank FROM employees;
결과
employee_id
department_id
salary
rank
101
10
9000
1
102
10
7000
2
103
10
7000
2
104
10
6000
4
3. DENSE_RANK()
설명
동일한 값이면 같은 순위를 부여, 이후 순위를 건너뛰지 않음
SQL 예제
SELECT employee_id, department_id, salary, DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dense_rank FROM employees;
결과
employee_id
department_id
salary
dense_rank
101
10
9000
1
102
10
7000
2
103
10
7000
2
104
10
6000
3
4. PERCENT_RANK()
설명
(RANK – 1) / (전체 행 수 – 1) 공식으로 백분율 순위 계산
SQL 예제
SELECT employee_id, department_id, salary, PERCENT_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS percent_rank FROM employees;
결과
employee_id
department_id
salary
percent_rank
101
10
9000
0.0
102
10
7000
0.5
103
10
7000
0.5
104
10
6000
1.0
5. LAG()
설명
이전 행의 값 가져오기 (NULL 허용)
SQL 예제
SELECT employee_id, department_id, salary, LAG(salary) OVER (PARTITION BY department_id ORDER BY salary DESC) AS prev_salary FROM employees;
결과
employee_id
department_id
salary
prev_salary
101
10
9000
NULL
102
10
7000
9000
103
10
7000
7000
6. LEAD()
설명
다음 행의 값 가져오기 (NULL 허용)
SQL 예제
SELECT employee_id, department_id, salary, LEAD(salary) OVER (PARTITION BY department_id ORDER BY salary DESC) AS next_salary FROM employees;
결과
employee_id
department_id
salary
next_salary
101
10
9000
7000
102
10
7000
7000
103
10
7000
6000
7. FIRST_VALUE()
설명
첫 번째 값 반환
SQL 예제
SELECT employee_id, department_id, salary, FIRST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary DESC) AS top_salary FROM employees;
8. LAST_VALUE()
설명
마지막 값 반환
SQL 예제
SELECT employee_id, department_id, salary, LAST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS bottom_salary FROM employees;
9. NTH_VALUE()
설명
특정 번째(n) 값 반환
SQL 예제
SELECT employee_id, department_id, salary, NTH_VALUE(salary, 2) OVER (PARTITION BY department_id ORDER BY salary DESC) AS second_salary FROM employees;
10. MEDIAN()
설명
중간 값 반환 (일부 DBMS에서 지원)
SELECT department_id, MEDIAN(salary) OVER (PARTITION BY department_id) AS median_salary FROM employees;
11. CUME_DIST() (누적 분포 함수)
🔹 설명
데이터 그룹 내에서 특정 값이 차지하는 누적 비율을 계산하는 함수
순위 기반 함수로, 해당 값이 속한 그룹에서 몇 번째 누적 비율인지 계산
같은 값이면 같은 비율을 반환하며, 항상 0보다 크고 1 이하
전체 행 수를 기준으로 누적된 값의 개수를 나눈 결과
🔹 공식
🔹 SQL 예제
SELECT employee_id, department_id, salary, CUME_DIST() OVER (PARTITION BY department_id ORDER BY salary DESC) AS cum_dist FROM employees;
🔹 결과값
employee_id
department_id
salary
cum_dist
101
10
9000
0.25
102
10
7000
0.50
103
10
7000
0.50
104
10
6000
1.00
🔹 설명
부서(department_id)별(PARTITION BY) 급여(salary DESC) 순으로 정렬하여 누적 분포를 계산
7000을 받는 두 명(102, 103)의 CUME_DIST 값이 동일
6000을 받는 104번 직원이 마지막 값이므로 1.00
12. RATIO_TO_REPORT() (비율 계산 함수)
🔹 설명
각 행의 특정 값이 그룹 내 전체 합에서 차지하는 비율을 반환
SUM(column)의 전체 합을 기준으로 개별 값의 비율을 계산
GROUP BY 없이 개별 행을 유지하면서 비율을 볼 때 유용
🔹 공식
🔹 SQL 예제
SELECT department_id, employee_id, salary, RATIO_TO_REPORT(salary) OVER (PARTITION BY department_id) AS salary_ratio FROM employees;
🔹 결과값
employee_id
department_id
salary
salary_ratio
101
10
9000
0.36
102
10
7000
0.28
103
10
7000
0.28
104
10
6000
0.24
🔹 설명
PARTITION BY department_id → 부서별 급여 합계를 기준으로 비율 계산