그룹으로 묶지 않고도 순위·누적·이전/다음 값을 계산하는 방법.
윈도우 함수
GROUP BY 는 행을 합쳐 버리지만, 윈도우 함수는 행을 그대로 둔 채 각 행 옆에 집계·순위 값을 덧붙입니다. 순위 매기기, 누적 합계, 이전 행과 비교 같은 분석을 한 번의 쿼리로 우아하게 풀 수 있습니다.
학습 목표
OVER와PARTITION BY의 구조를 이해합니다.ROW_NUMBER·RANK·DENSE_RANK로 순위를 매깁니다.LAG·LEAD로 이전·다음 행 값을 가져옵니다.ROWS BETWEEN프레임으로 누적 합계를 계산합니다.
OVER 와 PARTITION BY
윈도우 함수는 함수() OVER (...) 형태입니다. PARTITION BY 로 그룹을 나누고, ORDER BY 로 그룹 안 순서를 정합니다.
SELECT
name, department, salary,
AVG(salary) OVER (PARTITION BY department) AS 부서평균
FROM Employees;
GROUP BY 와 달리 행이 사라지지 않고, 각 직원 옆에 자기 부서 평균이 함께 표시됩니다.
| name | department | salary | 부서평균 |
|---|---|---|---|
| 민수 | Dev | 4,000,000 | 4,100,000 |
| 영희 | Dev | 4,200,000 | 4,100,000 |
순위 함수
SELECT
name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense
FROM Employees;
| 함수 | 동점 처리 |
|---|---|
ROW_NUMBER | 동점이어도 무조건 1,2,3 (고유 번호) |
RANK | 동점은 같은 순위, 다음은 건너뜀 (1,1,3) |
DENSE_RANK | 동점은 같은 순위, 다음은 연속 (1,1,2) |
💡 TIP — "각 그룹에서 1등만" 뽑으려면
ROW_NUMBER()로 번호를 매긴 뒤 바깥에서WHERE rn = 1로 거릅니다. 이 패턴은 실무에서 정말 자주 쓰입니다.
WITH Ranked AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
FROM Employees
)
SELECT * FROM Ranked WHERE rn = 1;
LAG / LEAD — 이전·다음 행
SELECT
order_date, amount,
LAG(amount) OVER (ORDER BY order_date) AS 전일,
LEAD(amount) OVER (ORDER BY order_date) AS 익일,
amount - LAG(amount) OVER (ORDER BY order_date) AS 증감
FROM DailySales;
LAG(col, n, 기본값) 으로 n칸 이전 값을, LEAD 로 이후 값을 가져옵니다. 전일 대비 증감처럼 행 간 비교에 안성맞춤입니다.
누적 합계와 프레임 (ROWS BETWEEN)
ORDER BY 를 준 집계 함수는 프레임을 지정해 누적·이동 계산을 합니다.
SELECT
order_date, amount,
-- 누적 합계
SUM(amount) OVER (
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS 누적합,
-- 최근 3일 이동 평균
AVG(amount) OVER (
ORDER BY order_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS 이동평균3일
FROM DailySales;
| 프레임 표현 | 의미 |
|---|---|
UNBOUNDED PRECEDING | 파티션 첫 행부터 |
n PRECEDING | 현재 기준 n행 앞 |
CURRENT ROW | 현재 행 |
UNBOUNDED FOLLOWING | 파티션 마지막 행까지 |
⚠️ 주의 —
ORDER BY만 주고 프레임을 생략하면 기본값은RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW입니다. 동점 행 처리 때문에 의도와 달라질 수 있으니, 누적 합계는ROWS프레임을 명시하는 것이 안전합니다.
요약
- 윈도우 함수는 행을 유지한 채 집계·순위 값을 각 행에 덧붙입니다.
PARTITION BY로 그룹을,ORDER BY로 그룹 내 순서를 정합니다.ROW_NUMBER/RANK/DENSE_RANK는 동점 처리 방식이 다릅니다.LAG/LEAD로 이전·다음 행 값을 비교합니다.ROWS BETWEEN프레임으로 누적 합계와 이동 평균을 계산합니다.
연습문제
- 부서별 급여 순위를
RANK로 매겨 출력하세요. - 각 부서에서 급여가 가장 높은 직원만 골라내세요.
- 일별 매출 테이블에서 전일 대비 증감액을
LAG로 계산하세요. - 일별 매출의 누적 합계를
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW로 구하세요.
힌트 — 2번은
ROW_NUMBER() ... WHERE rn = 1, 3번은amount - LAG(amount) OVER (ORDER BY order_date)입니다.
💡 연습문제 풀이
불러오는 중…
댓글 0
“MSSQL” 강좌에 대한 댓글입니다.