MSSQL에서 윈도우 함수(Window Function) 는
그룹핑 없이도 행 단위 결과를 유지하면서 집계, 순위, 누적 계산을 할 수 있는 기능이다.
기존 GROUP BY로는 해결하기 어려운 쿼리를
훨씬 직관적이고 성능 좋게 작성할 수 있다.
함수명 (컬럼)
OVER (
PARTITION BY 컬럼
ORDER BY 컬럼
ROWS | RANGE
)
PARTITION BY : 그룹 기준 ORDER BY : 윈도우 내 정렬 기준 ROWS / RANGE : 계산 범위 지정 | order_id | member_id | price | order_date |
|---|---|---|---|
| 1 | 1 | 10000 | 2024-01-01 |
| 2 | 1 | 20000 | 2024-01-05 |
| 3 | 2 | 15000 | 2024-01-03 |
| 4 | 2 | 30000 | 2024-01-10 |
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY member_id
ORDER BY order_date DESC
) AS rn
FROM Orders;
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY member_id
ORDER BY order_date DESC
) AS rn
FROM Orders
) t
WHERE rn = 1;
RANK() : 동일 순위 발생 시 다음 순위 건너뜀 DENSE_RANK() : 동일 순위 발생 시 다음 순위 연속 SELECT member_id,
price,
RANK() OVER (ORDER BY price DESC) AS rank,
DENSE_RANK() OVER (ORDER BY price DESC) AS dense_rank
FROM Orders;
SELECT order_id,
order_date,
price,
SUM(price) OVER (
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_price
FROM Orders;
SELECT order_id,
order_date,
price,
AVG(price) OVER (
ORDER BY order_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS avg_price
FROM Orders;
SELECT order_id,
member_id,
COUNT(*) OVER (PARTITION BY member_id) AS order_count
FROM Orders;
SELECT order_id,
order_date,
price,
LAG(price) OVER (ORDER BY order_date) AS prev_price,
LEAD(price) OVER (ORDER BY order_date) AS next_price
FROM Orders;
SELECT order_id,
price,
price - LAG(price) OVER (ORDER BY order_date) AS diff
FROM Orders;
⚠ LAST_VALUE는 범위 지정 필수
SELECT member_id,
order_date,
price,
FIRST_VALUE(price) OVER (
PARTITION BY member_id
ORDER BY order_date
) AS first_price,
LAST_VALUE(price) OVER (
PARTITION BY member_id
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_price
FROM Orders;
SELECT member_id,
order_date,
price,
SUM(price) OVER (
PARTITION BY member_id
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS member_total
FROM Orders;
SELECT member_id, SUM(price)
FROM Orders
GROUP BY member_id;
SELECT order_id,
member_id,
price,
SUM(price) OVER (PARTITION BY member_id) AS total_price
FROM Orders;
ORDER BY 없는 OVER는 전체 파티션 기준 WITH Ranked AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY order_date DESC) AS rn
FROM Orders
)
SELECT *
FROM Ranked
WHERE rn <= 10;
GROUP BY의 대체가 아닌 보완 관계