MySQL 문법 및 예제 정리 - PRECEDING, FOLLOWING, CURRENT ROW
MySQL 윈도우 함수의 PRECEDING, FOLLOWING, CURRENT ROW 옵션은 각 행에 대해 계산할 프레임(창) 범위를 지정한다. 프레임 정의를 정확히 이해하면 이동 평균, 누적 합계, 전후 행 비교를 한 줄의 SQL로 표현할 수 있다.
윈도우 프레임 동작 시각화 (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING):
────────────────────────────────────────────────────────────────
행 번호 │ 값 │ 1 PRECEDING │ CURRENT ROW │ 1 FOLLOWING │ SUM(프레임)
────────────────────────────────────────────────────────────────
1 │ 10 │ - │ O │ O │ 10+20 = 30
2 │ 20 │ O │ O │ O │ 10+20+30 = 60
3 │ 30 │ O │ O │ O │ 20+30+40 = 90
4 │ 40 │ O │ O │ - │ 30+40 = 70
────────────────────────────────────────────────────────────────
※ UNBOUNDED PRECEDING/FOLLOWING은 파티션의 처음/끝까지 확장됨.
윈도우 프레임의 주요 옵션
PRECEDING: 현재 행을 기준으로 앞쪽의 행들을 지정한다.N PRECEDING: 현재 행에서 앞으로 N개의 행
FOLLOWING: 현재 행을 기준으로 뒤쪽의 행들을 지정한다.N FOLLOWING: 현재 행에서 뒤로 N개의 행
CURRENT ROW: 현재 행을 프레임의 경계로 삼는다.ROWS에서는 현재 행 자체가,RANGE에서는 현재 행과ORDER BY값이 같은 행들(peer)이 경계가 된다1.UNBOUNDED PRECEDING: 윈도우 프레임의 시작을 파티션의 첫 번째 행으로 지정한다1.UNBOUNDED FOLLOWING: 윈도우 프레임의 끝을 파티션의 마지막 행으로 지정한다1.
프레임 시작 지정자는 프레임 끝 지정자보다 뒤에 올 수 없다. BETWEEN 2 FOLLOWING AND CURRENT ROW처럼 시작이 끝보다 뒤인 조합은 오류이며, BETWEEN CURRENT ROW AND 2 FOLLOWING 순서로 써야 한다1.
윈도우 함수 기본 구문
<윈도우 함수> OVER (PARTITION BY column ORDER BY column ROWS | RANGE BETWEEN <프레임 정의>)
ROWS: 실제 행의 개수를 기준으로 프레임을 설정한다.RANGE:ORDER BY값의 범위를 기준으로 프레임을 설정한다 (예: 날짜 또는 숫자 범위).
ROWS vs RANGE
ROWS: 실제로 행 개수를 기준으로 윈도우 프레임을 설정한다.- 예:
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW는 현재 행과 그 앞 2개의 행을 포함한다.
- 예:
RANGE: 값의 범위를 기준으로 윈도우 프레임을 설정한다.expr PRECEDING/expr FOLLOWING의 경계는 현재 행의 값에서expr을 뺀 값/더한 값과 같은 행들(peer)이다1.- 예:
RANGE BETWEEN INTERVAL 1 DAY PRECEDING AND CURRENT ROW는 날짜 값을 기준으로 프레임을 설정한다. RANGE에 숫자형expr을 쓰면ORDER BY도 숫자형 식이어야 하고,INTERVAL(날짜형)을 쓰면ORDER BY도 날짜형 식이어야 한다1.
- 예:
프레임 지정 옵션 설명
1. UNBOUNDED PRECEDING
- 처음부터 현재 행까지의 모든 행을 포함한다.
- “시작이 없을 만큼” 이전의 모든 행, 즉 파티션의 첫 행부터를 포함한다는 의미다1.
# 설명: 첫 번째 행부터 현재 행까지 누적 합계를 계산합니다.
SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
2. CURRENT ROW
- 현재 행을 프레임의 경계로 삼는다.
- 윈도우 프레임이 현재 행에서 시작하거나 끝날 때 사용한다.
RANGE에서는 현재 행과ORDER BY값이 같은 행들(peer)이 함께 포함된다1.
# 설명: 현재 행과 그 뒤에 있는 2개의 행에 대해 평균 급여를 계산합니다.
AVG(salary) OVER (ORDER BY hire_date ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING)
3. N PRECEDING
- 현재 행을 기준으로 앞으로 N개의 행을 포함한다.
# 설명: 현재 행에서 앞으로 3개의 행과 현재 행을 포함한 누적 합계를 계산합니다.
SUM(sales) OVER (ORDER BY sales_date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
4. N FOLLOWING
- 현재 행을 기준으로 뒤로 N개의 행을 포함한다.
# 설명: 현재 행과 그 뒤의 2개의 행에 대해 누적 합계를 계산합니다.
SUM(sales) OVER (ORDER BY sales_date ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING)
5. UNBOUNDED FOLLOWING
- 현재 행부터 끝까지 모든 행, 즉 파티션의 마지막 행까지를 포함한다1.
# 설명: 현재 행부터 마지막 행까지의 합계를 계산합니다.
SUM(sales) OVER (ORDER BY sales_date ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
윈도우 프레임의 제약과 주의점
ORDER BY유무가 기본 프레임을 바꾼다:ORDER BY가 있으면 기본 프레임은RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, 없으면 파티션 전체다. 같은 쿼리에ORDER BY를 추가하는 것만으로SUM()값이 달라질 수 있으므로, 집계 범위를 고정하려면 프레임 절을 직접 명시한다1.- 지원되지 않는 프레임 문법: MySQL은
GROUPS프레임 단위와 프레임의EXCLUDE절,IGNORE NULLS,FROM LAST를 파싱은 하지만 오류를 낸다. 실제로 쓸 수 있는 프레임 단위는ROWS와RANGE뿐이다2. - 행 값에 따라 변하는 동적 경계 미지원: 프레임 경계가 현재 행의 값에 의존하는 형태(
expr자리에 컬럼을 쓰는 형태)는 지원하지 않는다2. - 중첩 윈도우 함수와 집계 윈도우 함수의
DISTINCT미지원:COUNT(DISTINCT x) OVER (...)처럼 집계 윈도우 함수에DISTINCT를 쓰거나, 윈도우 함수의 결과를 다른 윈도우 함수에 바로 넣을 수 없다. 중첩이 필요하면 서브쿼리나 CTE로 한 단계 나눈다2. UPDATE/DELETE에서의 사용 제한: SQL 표준 제약으로, 윈도우 함수를UPDATE/DELETE의 갱신 대상 행을 정하는 데는 쓸 수 없고 서브쿼리에서 행을 선택하는 용도로만 쓸 수 있다. 윈도우 개수는 MySQL 8.0.28부터SELECT당 최대 127개다2.
예시
1. 누적 합계 (처음부터 현재까지)
# 설명: 첫 번째 행부터 현재 행까지의 누적 합계를 계산합니다.
SELECT
sales_date,
sales_amount,
SUM(sales_amount) OVER (ORDER BY sales_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_sales
FROM Sales;
2. 현재 행과 이전 2개의 행의 합계
# 설명: 현재 행과 그 앞의 2개 행의 합계를 계산합니다. 총 3개의 행에 대해 집계가 이루어집니다.
SELECT
sales_date,
sales_amount,
SUM(sales_amount) OVER (ORDER BY sales_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS window_sales
FROM Sales;
3. 현재 행과 다음 2개의 행에 대한 평균
# 설명: 현재 행과 그 뒤의 2개 행에 대한 평균을 계산합니다.
SELECT
sales_date,
sales_amount,
AVG(sales_amount) OVER (ORDER BY sales_date ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING) AS avg_sales
FROM Sales;
4. 현재 행과 모든 이후 행에 대한 최대값
# 설명: 현재 행부터 마지막 행까지의 `sales_amount` 값 중 최대값을 반환합니다.
SELECT
sales_date,
sales_amount,
MAX(sales_amount) OVER (ORDER BY sales_date ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS max_future_sales
FROM Sales;
References
-
MySQL 8.0 Reference Manual — 14.20.3 Window Function Frame Specification — 프레임 경계 지정자(
CURRENT ROW,UNBOUNDED PRECEDING/FOLLOWING,expr PRECEDING/FOLLOWING)의 의미,frame_start/frame_end순서 제약,ORDER BY유무에 따른 기본 프레임,RANGE와ORDER BY식 유형 요건. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 -
MySQL 8.0 Reference Manual — 14.20.5 Window Function Restrictions — 미지원 기능(
GROUPS/EXCLUDE/IGNORE NULLS/FROM LAST, 동적 프레임 경계, 중첩 윈도우 함수, 집계 윈도우 함수의DISTINCT),UPDATE/DELETE제약,SELECT당 윈도우 개수 상한. ↩ ↩2 ↩3 ↩4
댓글남기기