소스: sql-src/work_04_period_report/01_buckets.sql. 주문 표 orders 는 38행입니다(2024-01-10 ~ 2025-06-24). 컬럼은 id, cust, amt, ord_date 입니다.
SELECT
ord_date
, COUNT(*) AS cnt
, SUM(amt) AS amt
FROM orders
WHERE ord_date >= DATE '2025-06-01'
AND ord_date < DATE '2025-07-01'
GROUP BY ord_date
ORDER BY ord_date;ORD_DATE | CNT | AMT
-----------+-----+----
2025-06-03 | 2 | 800
2025-06-10 | 1 | 600
2025-06-24 | 1 | 400
(3행)주문이 있던 날짜만 나옵니다. 매출 0원인 날까지 보여야 하면 중급 10 에서 본 달력 조인으로 날짜를 채웁니다.
연·월을 두 컬럼으로 나누는 방식입니다.
SELECT
EXTRACT(YEAR FROM ord_date) AS yr
, EXTRACT(MONTH FROM ord_date) AS mo
, COUNT(*) AS cnt
, SUM(amt) AS amt
FROM orders
WHERE ord_date >= DATE '2025-01-01'
AND ord_date < DATE '2025-07-01'
GROUP BY EXTRACT(YEAR FROM ord_date), EXTRACT(MONTH FROM ord_date)
ORDER BY yr, mo;2025년 상반기는 1~5월이 각 2건, 6월이 4건이고 월 합계는 1050, 900, 1150, 950, 1200, 1800 입니다.
목표 표처럼 '2025-01' 문자 키와 맞출 때는 TO_CHAR(ord_date, 'YYYY-MM') 한 컬럼이 편합니다. H2 에서 모드와 무관하게 실행되고, 문자 키는 정렬이 날짜 순서와 같아 ORDER BY ym 이 안전합니다(소스 01_buckets.sql 의 3번, 2024-11 ~ 2025-02).
2024-12-29 부터 2025-01-05 사이 주문에 달력 연도와 ISO 연도·주를 나란히 붙입니다.
SELECT
ord_date
, EXTRACT(YEAR FROM ord_date) AS cal_yr
, EXTRACT(ISO_WEEK_YEAR FROM ord_date) AS iso_yr
, EXTRACT(ISO_WEEK FROM ord_date) AS iso_wk
FROM orders
WHERE ord_date >= DATE '2024-12-29'
AND ord_date < DATE '2025-01-06'
ORDER BY ord_date;ORD_DATE | CAL_YR | ISO_YR | ISO_WK
-----------+--------+--------+-------
2024-12-29 | 2024 | 2024 | 52
2024-12-30 | 2024 | 2025 | 1
2024-12-31 | 2024 | 2025 | 1
2025-01-02 | 2025 | 2025 | 1
(4행)2024-12-30 과 12-31 은 달력 연도 2024 인데 ISO 연도는 2025 이고 1주입니다. 2025-01-02 와 같은 주입니다. EXTRACT(ISO_WEEK ...) 표기는 H2 에서 되는 것이고 다른 DB 는 2.2 의 표를 봅니다.
ISO 연도·주로 묶고, 보고서에 보이기 좋게 주의 월요일 날짜를 함께 냅니다.
SELECT
EXTRACT(ISO_WEEK_YEAR FROM ord_date) AS iso_yr
, EXTRACT(ISO_WEEK FROM ord_date) AS iso_wk
, MIN(DATEADD('DAY', 1 - EXTRACT(ISO_DAY_OF_WEEK FROM ord_date), ord_date)) AS week_start
, COUNT(*) AS cnt
, SUM(amt) AS amt
FROM orders
WHERE ord_date >= DATE '2024-12-01'
AND ord_date < DATE '2025-02-01'
GROUP BY EXTRACT(ISO_WEEK_YEAR FROM ord_date), EXTRACT(ISO_WEEK FROM ord_date)
ORDER BY iso_yr, iso_wk;ISO_YR | ISO_WK | WEEK_START | CNT | AMT
-------+--------+------------+-----+-----
2024 | 52 | 2024-12-23 | 1 | 700
2025 | 1 | 2024-12-30 | 3 | 1000
2025 | 4 | 2025-01-20 | 1 | 600
(3행)2025년 1주는 2024-12-30 월요일에 시작해 주문 3건 1000 을 묶었습니다. 요일 번호(ISO_DAY_OF_WEEK, 월=1 ~ 일=7)를 써서 날짜에서 (요일 번호 - 1)일을 빼는 것이 월요일을 구하는 방법입니다. 주문이 없는 2·3주는 행이 없습니다.
기준일을 2025-06-15 로 고정하고, 이번 달 1일부터 기준일까지의 합계를 냅니다.
SELECT
SUM(CASE WHEN ord_date >= DATE '2025-06-01' AND ord_date < DATE '2025-06-16'
THEN amt ELSE 0 END) AS mtd_2025
, SUM(CASE WHEN ord_date >= DATE '2024-06-01' AND ord_date < DATE '2024-06-16'
THEN amt ELSE 0 END) AS mtd_2024
, SUM(CASE WHEN ord_date >= DATE '2025-06-01' AND ord_date < DATE '2025-07-01'
THEN amt ELSE 0 END) AS month_2025
FROM orders;MTD_2025 | MTD_2024 | MONTH_2025
---------+----------+-----------
1400 | 1000 | 1800
(1행)기준일이 포함되도록 끝은 "기준일 다음 날 미만" 인 < 2025-06-16 입니다. 6월 15일까지 1400 이고, 6월 24일 주문 400 은 아직 잡히지 않았습니다. 전년 같은 기간을 같은 쿼리에서 재려면 조건 날짜를 1년 전으로 바꿉니다.