在电商、零售等业务场景中,按月统计销售数据是数据分析的基础需求,通过SQL的GROUP BY子句结合日期函数,可以快速完成这类统计任务,不同数据库类型的日期函数存在差异,需要针对性选择使用。

核心实现逻辑
按月统计销售数据的核心思路是先通过日期函数从订单的时间字段中提取出年份和月份信息,再使用GROUP BY对提取出的年月信息进行分组,最后对分组后的销售金额、订单数量等字段进行聚合计算,得到每个月的统计结果。
不同数据库的日期函数与实现示例
MySQL数据库
MySQL中可以使用DATE_FORMAT函数提取日期的年月部分,语法为DATE_FORMAT(日期字段, '%Y-%m'),其中%Y代表四位年份,%m代表两位月份。
假设存在销售订单表sales,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | int | 订单ID |
| order_time | datetime | 下单时间 |
| amount | decimal(10,2) | 订单金额 |
按月统计每月的总销售额和订单数的SQL语句如下:
-- 按月统计总销售额和订单数
SELECT
DATE_FORMAT(order_time, '%Y-%m') AS sale_month, -- 提取年月
SUM(amount) AS total_amount, -- 总销售额
COUNT(id) AS order_count -- 订单数
FROM sales
GROUP BY sale_month -- 按年月分组
ORDER BY sale_month; -- 按年月排序
PostgreSQL数据库
PostgreSQL中可以使用TO_CHAR函数提取日期的年月部分,语法为TO_CHAR(日期字段, 'YYYY-MM'),也可以使用DATE_TRUNC函数将日期截断到月份,再提取对应信息。
同样基于上述sales表结构,按月统计的SQL语句如下:
-- 方式一:使用TO_CHAR函数
SELECT
TO_CHAR(order_time, 'YYYY-MM') AS sale_month,
SUM(amount) AS total_amount,
COUNT(id) AS order_count
FROM sales
GROUP BY sale_month
ORDER BY sale_month;
-- 方式二:使用DATE_TRUNC函数
SELECT
DATE_TRUNC('month', order_time) AS sale_month,
SUM(amount) AS total_amount,
COUNT(id) AS order_count
FROM sales
GROUP BY DATE_TRUNC('month', order_time)
ORDER BY sale_month;
SQL Server数据库
SQL Server中可以使用FORMAT函数或者DATEPART函数组合提取年月信息,FORMAT函数语法为FORMAT(日期字段, 'yyyy-MM'),DATEPART函数可以分别提取年份和月份再拼接。
按月统计的SQL语句如下:
-- 方式一:使用FORMAT函数
SELECT
FORMAT(order_time, 'yyyy-MM') AS sale_month,
SUM(amount) AS total_amount,
COUNT(id) AS order_count
FROM sales
GROUP BY FORMAT(order_time, 'yyyy-MM')
ORDER BY sale_month;
-- 方式二:使用DATEPART函数拼接
SELECT
CAST(DATEPART(YEAR, order_time) AS VARCHAR) + '-' + RIGHT('0' + CAST(DATEPART(MONTH, order_time) AS VARCHAR), 2) AS sale_month,
SUM(amount) AS total_amount,
COUNT(id) AS order_count
FROM sales
GROUP BY CAST(DATEPART(YEAR, order_time) AS VARCHAR) + '-' + RIGHT('0' + CAST(DATEPART(MONTH, order_time) AS VARCHAR), 2)
ORDER BY sale_month;
注意事项
- 如果订单时间字段包含时分秒信息,日期函数会自动忽略时分秒部分,只提取年月,不需要额外处理。
- 分组时GROUP BY后面的字段需要和SELECT中用于提取年月的表达式完全一致,否则会报错。
- 如果某个月没有销售数据,上述查询不会返回该月的结果,如果需要返回所有月份(包括无数据的月份),需要结合日期维度表使用LEFT JOIN实现。
- 聚合函数SUM计算金额时,如果amount字段存在NULL值,SUM会自动忽略NULL,不需要额外处理,若需要把NULL当作0计算,可以使用COALESCE函数转换。
扩展场景:按自然月统计并过滤数据
如果需要统计2024年1月到2024年6月的销售数据,可以在上述查询基础上添加WHERE条件过滤时间范围,示例如下(以MySQL为例):
SELECT
DATE_FORMAT(order_time, '%Y-%m') AS sale_month,
SUM(amount) AS total_amount,
COUNT(id) AS order_count
FROM sales
WHERE order_time >= '2024-01-01 00:00:00'
AND order_time < '2024-07-01 00:00:00' -- 小于7月1日,避免包含6月之后的数据
GROUP BY sale_month
ORDER BY sale_month;