最稳方式是用 date_format(order_time, '%y-%m') 分组,返回如'2023-05'的字符串,可排序且便于展示;避免用 year() 和 month() 拼接或在 where 中对 date_format 做等值判断。

MySQL里用 DATE_FORMAT 提取年月做分组
直接用 YEAR() 和 MONTH() 拼接会出问题:比如 2023-1 和 2023-10 会被当成同月(都是 1),必须保证月份两位对齐。最稳的方式是用 DATE_FORMAT(order_time, '%Y-%m'),它返回字符串如 '2023-05',天然可排序、可分组。
常见错误是写成 GROUP BY YEAR(order_time), MONTH(order_time) —— 这样虽然能分组,但结果里年月是分开两列,不方便后续处理或图表展示。
- 确保
order_time是DATETIME或DATE类型,如果是字符串,先用STR_TO_DATE()转换 - 如果表数据量大,记得给
order_time字段加索引,否则DATE_FORMAT会导致全表扫描 - 别在
WHERE条件里对DATE_FORMAT(order_time, '%Y-%m')做等值判断——无法走索引,应改用时间范围:order_time >= '2023-05-01' AND order_time
PostgreSQL 怎么按年月聚合?用 TO_CHAR 最省事
PostgreSQL 没有 DATE_FORMAT,对应的是 TO_CHAR(order_time, 'YYYY-MM')。注意大小写:YYYY 是四位年份,MM 是补零月份,YY 或 mm 都会错。
另一个可行但更重的方式是用 DATE_TRUNC('month', order_time),它返回的是时间戳(如 2023-05-01 00:00:00),适合需要进一步计算时间差的场景,但作为分组键不如字符串直观。
-
TO_CHAR返回文本类型,和 MySQL 的DATE_FORMAT行为一致,迁移时容易对齐 - 如果要按自然月统计(比如每月 1 号到当月最后一天),
DATE_TRUNC更可靠;但如果只是展示用,TO_CHAR更轻量 - 避免用
EXTRACT(YEAR FROM order_time)和EXTRACT(MONTH FROM order_time)组合分组——同样存在 2023-1 vs 2023-10 的歧义
SQL Server 分组时小心 FORMAT 函数的性能陷阱
SQL Server 2012+ 支持 FORMAT(order_time, 'yyyy-MM'),看起来简洁,但它是个高开销函数,尤其在大数据量下比 CONVERT 慢好几倍。生产环境更推荐用 CONVERT(CHAR(7), order_time, 120),它直接截取 '2023-05' 部分,不依赖 .NET 格式化引擎。
验证一下:CONVERT(CHAR(7), '2023-05-15 14:22:03', 120) 返回 '2023-05',刚好够用。
-
FORMAT在 WHERE 或 JOIN 中使用时,几乎必然导致索引失效,能不用就不用 - 如果字段是
SMALLDATETIME,注意它的精度只到秒,且默认四舍五入,可能影响边界数据归属 - SQL Server 2008 及更早版本不支持
FORMAT,得用RIGHT('0000' + CAST(YEAR(order_time) AS VARCHAR), 4) + '-' + RIGHT('00' + CAST(MONTH(order_time) AS VARCHAR), 2)—— 冗长但兼容
跨数据库统一写法?用标准 SQL 的 EXTRACT 加拼接
ANSI SQL 的 EXTRACT(YEAR FROM order_time) 和 EXTRACT(MONTH FROM order_time) 各数据库都支持,但不能直接拼成年月字符串。稳妥做法是:用 EXTRACT(YEAR FROM order_time) * 100 + EXTRACT(MONTH FROM order_time) 得到整数键(如 202305),再转成字符串或直接分组。
这个整数形式的好处是:可比较、可排序、无语言/区域设置干扰,而且大部分数据库对数值运算优化更好。
- PostgreSQL 和 MySQL 都支持该表达式;SQL Server 需换成
YEAR(order_time) * 100 + MONTH(order_time) - 整数键在 BI 工具里做时间轴切片时,比字符串更容易做同比环比计算
- 注意:这种方法无法直接用于
ORDER BY展示为'2023-05'格式,需额外CASE或应用层格式化
实际跑的时候,先看清楚你用的是哪个数据库,再挑对应函数;年月字符串看着方便,但背后索引能不能用、执行计划是否走最优路径,往往比写法“好看”重要得多。











