必须使用日历维表dim_calendar,预填is_workday标识工作日/非工作日,JOIN时统一日期精度(如CAST(order_date AS DATE)),避免函数作用于维表字段导致索引失效,分组统计优先用is_workday而非holiday_name。

必须用日历维表,不能靠 DATEPART 或 WEEKDAY
DATEPART(WEEKDAY, ...) 或 DATENAME(WEEKDAY, ...) 只能识别周六、周日,完全无法处理调休(如 2024 年 2 月 4 日周日上班)或法定假日(如 2024 年 2 月 10 日星期六放假)。硬编码 CASE WHEN 列出节假日也极难维护——每年国务院通知一出就得改 SQL。唯一靠谱做法是建一张 dim_calendar 维表,人工或脚本预填好每一年的 is_workday 值。
JOIN 时日期类型必须对齐,否则静默失败
业务表里的时间字段(比如 order_date)通常是 DATETIME 或 TIMESTAMP,而日历维表的 date_key 应该是 DATE 类型。JOIN 条件里必须统一精度:
- SQL Server / PostgreSQL:用
CAST(o.order_date AS DATE) = c.date_key - MySQL:用
DATE(o.order_date) = c.date_key(注意DATE()函数在大表上可能不走索引,建议提前加函数索引) - Oracle:用
TRUNC(o.order_date) = c.date_key - 千万别在维表字段上套函数,比如
CAST(c.date_key AS DATE),否则索引失效
分组统计时 is_workday 是最稳的分组键
is_workday 字段(值为 1/0 或 TRUE/FALSE)比靠 holiday_name IS NOT NULL 推断更可靠——它能明确标识调休日(当天是周末但上班)和补班日(当天是工作日但放假)。典型写法:
SELECT c.is_workday, COUNT(*) AS cnt, SUM(o.amount) AS total_amount FROM orders o JOIN dim_calendar c ON CAST(o.order_date AS DATE) = c.date_key WHERE o.order_date >= '2026-01-01' GROUP BY c.is_workday;
返回两行:一行 is_workday = 1(工作日),一行 is_workday = 0(含周末 + 法定假日 + 调休放假日)。
维表字段和覆盖范围容易被忽略
最小可用的 dim_calendar 至少要三列:date_key(DATE 类型主键)、is_workday(TINYINT 或 BOOLEAN)、holiday_name(VARCHAR,可空)。别省略 is_workday ——只存节日名称根本没法处理调休;也别用字符串存日期(如 '20240101'),否则 JOIN 时得反复 CONVERT,易出错。覆盖时间范围必须大于业务数据跨度,比如查 2023–2026 年数据,表里就得有这四年每天的记录,缺一天就漏一条统计。

















