mat(moving annual total)指截至当前月的过去12个月(含当月)滚动累计值,需动态滑动、按月对齐、跨年不中断;实现时须先补全月份序列再用sum() over (order by month_start rows between 11 preceding and current row)。

什么是MAT(Moving Annual Total)?
MAT不是SQL标准函数,而是业务术语,指“截至当前月的过去12个月(含当月)的累计值”。比如2024年6月的MAT销售额 = 2023年7月到2024年6月这12个月的销售额总和。关键点在于:窗口必须动态滑动、按月对齐、跨年不中断。
SUM() OVER ()怎么写滚动12个月窗口?
核心是用ROWS BETWEEN 11 PRECEDING AND CURRENT ROW——但前提是数据已按月粒度聚合且严格连续(无缺失月份)。若原始数据是日粒度或存在月份空缺,直接套用会漏算或错算。
- 先确保时间字段是
DATE类型且已归一为每月第一天(如用DATE_TRUNC('month', order_date)或MAKE_DATE(YEAR, MONTH, 1)) - 按该月首日排序:
ORDER BY month_start - 窗口定义必须用
ROWS而非RANGE(后者依赖值范围,对日期不稳健) - 示例(PostgreSQL):
SUM(sales) OVER (ORDER BY month_start ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS mat_sales
遇到月份缺失怎么办?补全后再算MAT
真实业务中常有某月无交易,导致ROWS BETWEEN 11 PRECEDING实际只覆盖10行甚至更少——MAT就变成“过去10个月”而非“滚动12个月”。必须先生成完整月份序列,再左连接业务数据。
- 用
GENERATE_SERIES()(PostgreSQL)、SEQUENCE(Databricks)或递归CTE生成目标时间段内所有年月 - 与原始销售表按
year_month左连接,空值补0 - 再在补全后的结果上跑
SUM() OVER (ORDER BY ... ROWS BETWEEN 11 PRECEDING ...) - 注意:补零后,2023年7月的MAT才真正包含从2023年7月起的首12个值;否则早期月份MAT会严重偏低
不同数据库对DATE窗口的支持差异
MySQL 8.0+ 和 SQL Server 2012+ 支持ROWS,但不支持直接用INTERVAL表达“过去12个月”(如RANGE BETWEEN INTERVAL '11 months' PRECEDING AND CURRENT ROW),这个语法仅Snowflake、BigQuery、Databricks部分支持,且行为未必一致。
- Snowflake:可用
RANGE BETWEEN INTERVAL '11 months' PRECEDING AND CURRENT ROW,但要求排序列是DATE且索引友好 - BigQuery:
RANGE只支持数字列,日期必须转为DATE_DIFF(CURRENT_DATE(), date_col, MONTH)再用ROWS - Oracle:需用
ADD_MONTHS()配合子查询模拟,原生窗口不认日期间隔 - 结论:跨库可移植性最强的方案仍是“补全月份 +
ROWS BETWEEN 11 PRECEDING”










