如何在SQL中获取两个日期之间的月份编号
在SQL中获取两个日期之间的月份编号
根据不同的SQL数据库,实现方式略有差异,核心逻辑是忽略日期中的日部分,仅基于年月生成连续的月份编号,以下是主流数据库的解决方案:
SQL Server
使用递归CTE生成连续的月份序列,再格式化为两位数字的编号:
DECLARE @StartDate DATE = '2023-01-04', @EndDate DATE = '2023-05-04'; WITH MonthSeries AS ( SELECT DATEFROMPARTS(YEAR(@StartDate), MONTH(@StartDate), 1) AS MonthStart UNION ALL SELECT DATEADD(MONTH, 1, MonthStart) FROM MonthSeries WHERE MonthStart < DATEFROMPARTS(YEAR(@EndDate), MONTH(@EndDate), 1) ) SELECT FORMAT(MonthStart, 'MM') AS MonthNumber FROM MonthSeries;
说明
- 用
DATEFROMPARTS把起始/结束日期转为当月第一天,彻底忽略具体日的影响 - 递归CTE生成从起始月到结束月的所有月份第一天
- 用
FORMAT函数将月份格式化为两位数字的编号
MySQL(8.0+)
通过递归CTE实现连续月份生成:
SET @StartDate = '2023-01-04', @EndDate = '2023-05-04'; WITH MonthSeries AS ( SELECT STR_TO_DATE(CONCAT(YEAR(@StartDate), '-', MONTH(@StartDate), '-01'), '%Y-%m-%d') AS MonthStart UNION ALL SELECT DATE_ADD(MonthStart, INTERVAL 1 MONTH) FROM MonthSeries WHERE MonthStart < STR_TO_DATE(CONCAT(YEAR(@EndDate), '-', MONTH(@EndDate), '-01'), '%Y-%m-%d') ) SELECT DATE_FORMAT(MonthStart, '%m') AS MonthNumber FROM MonthSeries;
说明
- 通过
STR_TO_DATE和CONCAT构造当月第一天,消除日部分的干扰 - 递归生成连续的月份区间
- 用
DATE_FORMAT输出两位格式的月份编号
PostgreSQL
利用generate_series函数直接生成月份序列:
WITH params AS ( SELECT DATE_TRUNC('month', '2023-01-04'::DATE) AS start_month, DATE_TRUNC('month', '2023-05-04'::DATE) AS end_month ) SELECT TO_CHAR(generate_series(start_month, end_month, '1 month'::interval), 'MM') AS MonthNumber FROM params;
说明
DATE_TRUNC('month', ...)将日期截断到当月第一天,忽略日部分generate_series直接生成从起始月到结束月的连续月份区间TO_CHAR将月份格式化为两位数字
跨年度场景适配
如果日期范围跨年度,比如2023-11-15到2024-02-20,上述代码会自动输出11、12、01、02,无需额外调整。
内容的提问来源于stack exchange,提问作者malcolm richard
相关产品推荐
相关产品推荐

