데이터베이스

SQL 윈도우 함수(Window Function)

SQL 윈도우 함수(Window Function) 는 데이터베이스에서 행(row) 단위로 연산을 수행하면서도, 기존 행(row)들을 그대로 유지하는 함수입니다.
GROUP BY와 달리 개별 행을 제거하지 않고 그룹 내에서 연산을 수행할 수 있습니다.

🏗 1. 윈도우 함수의 특징

기존 행을 유지하면서 그룹별 연산 수행

  • 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, …OO
RANK()동일한 값에 동일한 순위, 이후 순위 건너뜀1, 2, 2, 4, …OO
DENSE_RANK()동일한 값에 동일한 순위, 이후 순위 건너뛰지 않음1, 2, 2, 3, …OO
PERCENT_RANK()(RANK – 1) / (전체 행 수 – 1)로 백분율 순위0.0 ~ 1.0OO
LAG()이전 행의 값 가져오기이전 행 값 또는 NULLOX
LEAD()다음 행의 값 가져오기다음 행 값 또는 NULLOX
FIRST_VALUE()파티션 내 첫 번째 값 반환첫 번째 값OO
LAST_VALUE()파티션 내 마지막 값 반환마지막 값OO
NTH_VALUE()특정 번째(n) 값 반환n번째 값OO
MEDIAN()중간 값 반환 (일부 DBMS에서 지원)중간값OO
함수명설명반환 값PARTITION BY 사용 여부ORDER BY 필수 여부주요 활용
CUME_DIST()특정 값이 그룹 내에서 차지하는 누적 비율0 < 값 ≤ 1.0OO누적 분포 계산
RATIO_TO_REPORT()특정 값이 전체 합계에서 차지하는 비율0 ≤ 값 ≤ 1.0OX전체 대비 특정 행 비율 계산
NTILE(n)데이터를 n개의 그룹으로 나누어 그룹 번호를 반환1 ~ nOO데이터 그룹화

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_iddepartment_idsalaryrow_num
1011090001
1021070002
1031060003

2. RANK()

설명

  • 동일한 값이면 같은 순위를 부여, 이후 순위 건너뜀

SQL 예제

SELECT 
employee_id,
department_id,
salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank
FROM employees;

결과

employee_iddepartment_idsalaryrank
1011090001
1021070002
1031070002
1041060004

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_iddepartment_idsalarydense_rank
1011090001
1021070002
1031070002
1041060003

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_iddepartment_idsalarypercent_rank
1011090000.0
1021070000.5
1031070000.5
1041060001.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_iddepartment_idsalaryprev_salary
101109000NULL
1021070009000
1031070007000

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_iddepartment_idsalarynext_salary
1011090007000
1021070007000
1031070006000

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_iddepartment_idsalarycum_dist
1011090000.25
1021070000.50
1031070000.50
1041060001.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_iddepartment_idsalarysalary_ratio
1011090000.36
1021070000.28
1031070000.28
1041060000.24

🔹 설명

  • PARTITION BY department_id부서별 급여 합계를 기준으로 비율 계산
  • 부서 10번(department_id=10)의 전체 급여 합계:
    9000 + 7000 + 7000 + 6000 = 29000
  • 개별 급여를 29000으로 나눈 비율을 반환
    • 9000 / 29000 = 0.36
    • 7000 / 29000 = 0.28
    • 6000 / 29000 = 0.24

13. NTILE(n) (그룹 나누기 함수)

🔹 설명

  • 데이터를 n개의 동일한 크기의 그룹(타일)으로 나누어 그룹 번호를 부여
  • 사분위수, 백분위수와 같은 데이터 분할 분석에 사용
  • NTILE(4) → 데이터를 4등분(사분위) 해서 각 그룹에 순서를 부여

🔹 SQL 예제

SELECT 
employee_id,
department_id,
salary,
NTILE(4) OVER (PARTITION BY department_id ORDER BY salary DESC) AS quartile
FROM employees;

🔹 결과값

employee_iddepartment_idsalaryquartile
1011090001
1021070002
1031070003
1041060004

🔹 설명

  • PARTITION BY department_id부서별 그룹화
  • ORDER BY salary DESC급여 높은 순서로 정렬 후 그룹 배정
  • NTILE(4)데이터를 4개 그룹으로 나누어 순위 부여
    • 9000 (1등급)
    • 7000 (2등급)
    • 7000 (3등급)
    • 6000 (4등급)

zerg96

Recent Posts

타입스크립트 (TypeScript)

1. 타입스크립트 개요 타입스크립트(TypeScript)는 마이크로소프트(Microsoft)가 개발한 자바스크립트(JavaScript)의 상위 집합(Superset) 언어입니다.즉, 자바스크립트에 정적 타입(Static Type)을 추가하고,…

5개월 ago

노트북(윈도우)에서 아이폰 유선 테더링 하기

윈도우 운영체제의 노트북에서는 iPhone 유선 테더링이 잘 안되는 경우가 많습니다. 보통 iPhone의 드라이버가 설치가 안되있어서인…

6개월 ago

오라클 래치(Latch)

오라클 데이터베이스의 성능을 논할 때, 내부적으로 발생하는 경합(Contention)은 피할 수 없는 주제다. 특히 다수의 프로세스가…

7개월 ago

사장님도 3표, 나도 3표? ‘3%룰’ 완전 정복!

안녕하세요, 혹시 이런 생각해 본 적 없으신가요? "내가 투자한 회사는 누가 감시하고, 어떻게 운영될까?" 오늘은…

7개월 ago

Vector Store(벡터 스토어)

'벡터 스토어' 완벽 가이드: AI 시대, 데이터의 새로운 심장을 만나다 IT 업계는 인공지능(AI)이라는 거대한 패러다임의…

7개월 ago

Gemini CLI (재미나이 CLI)

1. Gemini CLI란 무엇인가요? Gemini CLI는 터미널 환경에서 직접 Gemini 모델과 상호작용할 수 있도록 만들어진…

7개월 ago