dev.syw

그룹으로 묶지 않고도 순위·누적·이전/다음 값을 계산하는 방법.

윈도우 함수

GROUP BY 는 행을 합쳐 버리지만, 윈도우 함수는 행을 그대로 둔 채 각 행 옆에 집계·순위 값을 덧붙입니다. 순위 매기기, 누적 합계, 이전 행과 비교 같은 분석을 한 번의 쿼리로 우아하게 풀 수 있습니다.

학습 목표

  • OVERPARTITION 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 와 달리 행이 사라지지 않고, 각 직원 옆에 자기 부서 평균이 함께 표시됩니다.

namedepartmentsalary부서평균
민수Dev4,000,0004,100,000
영희Dev4,200,0004,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 이동평균3FROM 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 프레임으로 누적 합계와 이동 평균을 계산합니다.

연습문제

  1. 부서별 급여 순위를 RANK 로 매겨 출력하세요.
  2. 각 부서에서 급여가 가장 높은 직원만 골라내세요.
  3. 일별 매출 테이블에서 전일 대비 증감액을 LAG 로 계산하세요.
  4. 일별 매출의 누적 합계를 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 로 구하세요.

힌트 — 2번은 ROW_NUMBER() ... WHERE rn = 1, 3번은 amount - LAG(amount) OVER (ORDER BY order_date) 입니다.

💡 연습문제 풀이

불러오는 중…

함께 보면 좋은 자료

댓글 0

MSSQL” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.