SQL统计两个日期之间完整月数的实现方法
问题根因
原代码使用的DATEDIFF(mm, 起始日期, 结束日期),计算逻辑仅比对两个日期所属的月份刻度差,不校验实际间隔是否满足完整月份周期:只要两个日期跨过自然月边界,就会累加月份计数,因此才会出现2021-03-03到2021-05-02被统计为2个月的偏差。
本次需求的核心统计规则为:仅当结束日期到达起始日期对应偏移整月的同一天时,才计入完整月份。按该规则,2021-03-03起始的周期,需到2021-04-03才算满1个月,到2021-05-03才算满2个月;2021-05-02距离满2个月还差1天,因此最终应计数为1。
实现方案
适配当前规则的最简写法
通过比对两个日期的「日」字段,判断最后一个未完成的月份是否需要扣除:
declare @startdate date='2021-03-03'; declare @enddate date='2021-05-02'; select datediff(mm,@startdate,@enddate) -- 若结束日期的「日」早于起始日期的「日」,说明最后一个整月未凑齐,扣除计数 - case when day(@enddate) < day(@startdate) then 1 else 0 end as full_month_count;
上述代码的返回结果为1,完全匹配预期。
校验用例
- start=2021-03-03,end=2021-04-03 → 返回1(刚好满1个完整月)
- start=2021-03-03,end=2021-04-02 → 返回0(距满1个月还差1天,不计数)
- start=2021-03-03,end=2021-05-03 → 返回2(刚好满2个完整月)
- 示例场景start=2021-03-03,end=2021-05-02 → 返回1
兼容月底边界的通用写法
如果业务中存在起始日为月底(比如1月31日)、后续月份无对应同日的场景(比如2月没有31日),纯对比DAY()的写法会出现统计偏差,可改用日期偏移校验的逻辑自动适配月底场景:
declare @startdate date='2021-01-31'; declare @enddate date='2021-02-28'; select case -- 若结束日期大于等于「起始日期偏移N个月的对齐日期」,则N为最终计数 when @enddate >= dateadd(mm, datediff(mm, @startdate, @enddate), @startdate) then datediff(mm, @startdate, @enddate) -- 否则扣除1个月的计数 else datediff(mm, @startdate, @enddate) - 1 end as full_month_count;
该写法会自动适配SQL中DATEADD的日期溢出逻辑:比如2021-01-31偏移1个月时,会自动返回2021-02-28(2月最后一天),因此2021-02-28会被判定为刚好满1个完整月,符合常规业务统计习惯。
内容的提问来源于stack exchange,提问作者sparc
相关产品推荐
相关产品推荐

