2. 핵심 원리
2.1 버킷: 날짜를 묶음 키로 바꾼다
버킷은 날짜를 일·주·월 같은 묶음 하나로 바꾼 값입니다. 버킷 컬럼은 SELECT 와 GROUP BY 에서만 만들고, 기간 조건은 날짜 범위로 겁니다.
범위 조건의 모양은 ord_date >= DATE '2025-06-01' AND ord_date < DATE '2025-07-01' 입니다.
WHERE EXTRACT(MONTH FROM ord_date) = 6 처럼 컬럼에 함수를 씌우면 ord_date 인덱스를 못 씁니다. 결과는 같아도 테이블 전체를 읽습니다. 범위 조건은 끝이 다음 달 1일 미만(<)이라 마지막 날의 시각이 섞여도 빠지지 않습니다.
핵심조건은
>= 시작 AND < 다음 시작으로 걸고, 버킷은 SELECT·GROUP BY 에서만 만듭니다.
2.2 월·주 버킷은 DB마다 표기가 다르다
같은 월 버킷도 DB 마다 함수가 다릅니다. 표에서 H2 로 실행한 것은 표준 EXTRACT 와 Oracle 모드 TO_CHAR 뿐입니다.
| 용도 | Oracle · Tibero | MySQL |
|---|---|---|
| 월 문자 | TO_CHAR(d, 'YYYY-MM') |
DATE_FORMAT(d, '%Y-%m') |
| 월 첫날 | TRUNC(d, 'MM') |
DATE_SUB(d, INTERVAL DAYOFMONTH(d) - 1 DAY) |
| ISO 주 번호 | TO_CHAR(d, 'IW') |
WEEK(d, 3) |
| ISO 연도 | TO_CHAR(d, 'IYYY') |
YEARWEEK(d, 3) 의 앞 4자리 |
| 주 시작(월요일) | TRUNC(d, 'IW') |
계산 필요 |
| 용도 | MSSQL |
|---|---|
| 월 문자 | FORMAT(d, 'yyyy-MM')(2012, 느림), CONVERT(CHAR(7), d, 120) |
| 월 첫날 | DATEFROMPARTS(YEAR(d), MONTH(d), 1)(2012) |
| ISO 주 번호 | DATEPART(ISO_WEEK, d)(2008 부터) |
| 연·월 분리 | YEAR(d), MONTH(d) |
MSSQL 의 FORMAT 은 .NET 서식을 써서 행마다 호출 비용이 크므로 대량 집계에는 CONVERT 나 DATEFROMPARTS 를 씁니다. MySQL 의 WEEK(d, 3) 에서 3 은 ISO 방식(월요일 시작, 1~53주)을 뜻합니다. YEARWEEK(d, 3) 은 ISO 연도와 주를 합친 202501 같은 숫자를 줍니다.
2.3 ISO 주와 연말·연초
ISO 주는 월요일에 시작하고, 그 주의 목요일이 속한 해가 그 주의 연도입니다. 그래서 연말의 며칠이 다음 해의 1주에 들어갈 수 있습니다. 2024-12-30(월)~2024-12-31(화)은 달력으로는 2024년이지만 ISO 로는 2025년 1주입니다.
"연도-주" 로 묶을 때 달력 연도를 쓰면 2024년 52주와 2025년 1주 사이에서 주 하나가 둘로 쪼개지거나 엉뚱한 해에 붙습니다. ISO 연도를 함께 쓰거나, 주의 월요일 날짜 하나를 묶음 키로 쓰면 안전합니다.
MSSQL 의 DATEPART(WEEK, d) 는 ISO 주가 아닙니다. 1월 1일이 속한 주를 1주로 세고 한 주의 시작 요일은 SET DATEFIRST 에 따라 달라서 ISO 와 값이 다릅니다.
주의주 번호는 반드시 ISO 함수(
IW,WEEK(d, 3),ISO_WEEK)를 쓰고, 연도는 ISO 연도로 짝을 맞춥니다. 달력 연도와 섞으면 연말·연초 주가 틀립니다.
2.4 전년 동월 비교와 빈 달
월 매출 표에서 전년 동월을 붙이는 방법은 둘입니다.
| 방식 | 뜻 | 빈 달이 있으면 |
|---|---|---|
LAG(amt, 12) |
12행 전 값 | 한 달씩 밀림 |
| 연-1 자기 조인 | 같은 월, 연도 -1 | 정확함(짝 없으면 NULL) |
LAG(amt, 12) 는 12개월 전이 아니라 12행 전입니다. 집계 결과에 빠진 달이 있으면 행이 하나 줄어서 그 뒤 모든 행이 한 달 이전 값을 가져옵니다. 연-1 조인은 p.yr = c.yr - 1 AND p.mo = c.mo 로 같은 달을 직접 찾으므로 밀리지 않습니다.
2.5 증감률·달성률·누적 달성률
세 지표는 모두 "분자 * 100.0 / 분모" 모양입니다.
| 지표 | 식 |
|---|---|
| 전년 대비 증감률(%) | (올해 - 전년) * 100.0 / 전년 |
| 목표 달성률(%) | 실적 * 100.0 / 목표 |
| 누적 달성률(%) | 누적 실적 * 100.0 / 누적 목표 |
100.0 을 곱하는 이유는 MSSQL 에서 INT 끼리 나누면 정수로 잘리기 때문입니다. 분모가 0 이거나 NULL 인 달은 NULLIF(분모, 0) 로 NULL 을 만들어 0 나누기 오류를 피합니다.
누적은 SUM(x) OVER (PARTITION BY 연도 ORDER BY 월) 입니다. 연도로 나누므로 1월에 누적이 다시 시작합니다. 누적 달성률은 각 월 달성률의 평균이 아니라 누적 실적을 누적 목표로 나눈 값이라는 점이 중요합니다(고급 02 윈도 프레임).