月度销售额同比是指将今年某个月的销售额与去年同月销售额相比得出的增长率,核心是“同月比”,计算公式为(本月销售额-去年同月销售额)÷去年同月销售额×100%,需用DATE_FORMAT与DATE_SUB构造年月键并JOIN对齐,务必用NULLIF防除零。

什么是月度销售额同比?
月度销售额同比,就是拿今年某个月的销售额,和去年同月的销售额相比,算出增长率。核心是“同月比”,不是和上个月比(那是环比)。计算公式是:(本月销售额 - 去年同月销售额) / 去年同月销售额,结果通常乘以 100 得到百分比。
用 DATE_SUB 和 JOIN 拉出去年同月数据
MySQL 最常用也最稳的做法:把当前月数据和去年同月数据在同一行对齐,再计算。关键在构造去年同月的时间条件。
- 用
DATE_FORMAT(order_date, '%Y-%m')提取年月,作为分组依据 - 用
DATE_SUB把当前月往前推 12 个月,生成去年同月的年月字符串:DATE_FORMAT(DATE_SUB(order_date, INTERVAL 12 MONTH), '%Y-%m') - 用两个子查询或 CTE 分别聚合「当月」和「去年同月」销售额,再按年月字段
JOIN
示例片段(MySQL):
WITH curr AS ( SELECT DATE_FORMAT(order_date, '%Y-%m') AS ym, SUM(amount) AS sales FROM orders WHERE order_date >= '2024-01-01' GROUP BY DATE_FORMAT(order_date, '%Y-%m') ), last AS ( SELECT DATE_FORMAT(DATE_SUB(order_date, INTERVAL 12 MONTH), '%Y-%m') AS ym, SUM(amount) AS last_sales FROM orders WHERE order_date >= '2023-01-01' AND order_date < '2024-01-01' GROUP BY DATE_FORMAT(DATE_SUB(order_date, INTERVAL 12 MONTH), '%Y-%m') ) SELECT c.ym, c.sales, l.last_sales, ROUND((c.sales - l.last_sales) / NULLIF(l.last_sales, 0), 4) AS yoy_rate FROM curr c LEFT JOIN last l ON c.ym = l.ym;
PostgreSQL 或 SQL Server 怎么写?
函数名和语法略有不同,但逻辑一致:先归一化年月,再跨年对齐。重点注意日期函数差异:
- PostgreSQL:用
TO_CHAR(order_date, 'YYYY-MM')替代DATE_FORMAT;用order_date - INTERVAL '12 months'替代DATE_SUB - SQL Server:用
FORMAT(order_date, 'yyyy-MM')或CONVERT(VARCHAR(7), order_date, 120);用DATEADD(MONTH, -12, order_date) - 所有数据库都建议加
NULLIF(..., 0)防止除零错误,尤其去年同月没数据时
容易被忽略的坑
实际跑起来经常出错,不是语法问题,而是业务逻辑断层:
- 订单时间用的是下单时间还是发货时间?两者口径不一致会导致同比失真
- 去年同月数据量极少(比如新业务刚起步),
last_sales为 0 或 NULL,直接除会报错或得NULL—— 必须用NULLIF或CASE WHEN处理 - 没过滤掉已取消/退款订单,导致当月销售额虚高,同比放大偏差
- 跨年时没限制时间范围,比如查 2024 年 3 月同比,却把 2023 年全年的数据都扫进
last子查询,性能爆炸
真正难的不是写 SQL,是确认「同比」背后每一分钱是否可比。时间、状态、币种、业务线,漏掉一个维度,结果就不可信。

















