需求:報表展示某月 (如 11 月) 每一天的數據。若某天無數據,自動取「最近一天有數據的記錄」填補 (如 11/30 無數據,取 11/28 數據)。
核心思路:
LAST_VALUE 或相關邏輯向前填充最近非空值。WITH date_series AS (
-- 生成 2023-11 全月日期
SELECT generate_series('2023-11-01'::date, '2023-11-30'::date, '1 day')::date AS dt
),
raw_data AS (
-- 原始業務數據
SELECT record_date, value FROM business_table
WHERE record_date BETWEEN '2023-11-01' AND '2023-11-30'
),
joined AS (
-- 左連接:保留所有日期
SELECT ds.dt, rd.value
FROM date_series ds
LEFT JOIN raw_data rd ON ds.dt = rd.record_date
)
SELECT
dt,
-- 向前填充:取當前行及之前最近的非空 value
LAST_VALUE(value) IGNORE NULLS OVER (ORDER BY dt
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS filled_value
FROM joined
ORDER BY dt;
WITH RECURSIVE date_series AS (
SELECT '2023-11-01' AS dt
UNION ALL
SELECT DATE_ADD(dt, INTERVAL 1 DAY) FROM date_series WHERE dt < '2023-11-30'
),
joined AS (
SELECT ds.dt, bt.value
FROM date_series ds
LEFT JOIN business_table bt ON ds.dt = bt.record_date
)
SELECT
dt,
-- MySQL 8.0 不支持 IGNORE NULLS,需用變量或子查詢模擬
(SELECT value FROM joined j2
WHERE j2.dt <= j1.dt AND j2.value IS NOT NULL
ORDER BY j2.dt DESC LIMIT 1) AS filled_value
FROM joined j1
ORDER BY dt;
若不願改動 SQL,可在報表設計器中實現:
=IF(ISBLANK(value), PREVIOUS(value), value)Prev()、LastNonBlank())。generate_series 時可用遞歸 CTE、數字表、或應用層生成列表傳入。record_date 必須建立索引。採用 **SQL 方案 + 視圖封裝**,將填充邏輯下沉到數據層,報表只負責展示,是架構最清晰、效能最穩健的選擇。