求更简洁的SQL按月计算指定日期区间内的日期范围方案
更简洁的SQL月度日期区间计算实现
原代码能实现指定日期区间内的月度日期范围计算,但存在步骤冗余、逻辑繁琐的问题,以下是两种更简洁的优化方案:
方案一:简化递归CTE逻辑,直接处理最终结果
DECLARE @FromDate DATE = '2023-06-01' DECLARE @ToDate DATE = '2023-08-05' ;WITH MonthlyRanges AS ( SELECT 1 AS RowNo, @FromDate AS FromDate, EOMONTH(@FromDate) AS OriginalEndDate, DATENAME(MONTH, @FromDate) + '-' + CAST(YEAR(@FromDate) AS VARCHAR(4)) AS YearMonth UNION ALL SELECT RowNo + 1, DATEADD(MONTH, 1, FromDate), EOMONTH(DATEADD(MONTH, 1, FromDate)), DATENAME(MONTH, DATEADD(MONTH, 1, FromDate)) + '-' + CAST(YEAR(DATEADD(MONTH, 1, FromDate)) AS VARCHAR(4)) FROM MonthlyRanges WHERE DATEADD(MONTH, 1, FromDate) <= @ToDate ) SELECT RowNo, FromDate, CASE WHEN OriginalEndDate > @ToDate THEN @ToDate ELSE OriginalEndDate END AS ToDate, YearMonth FROM MonthlyRanges OPTION (MAXRECURSION 0) -- 当日期区间超过100个月时需添加,解除递归层数限制
改进点:
- 移除冗余的表变量,直接通过CTE生成结果后处理最后一个区间的结束日期,减少中间操作
- 简化CTE内的日期计算逻辑,避免重复嵌套调用
EOMONTH函数 - 用
CASE语句在最终查询中直接修正最后一个月的结束日期,无需先插入再删除更新的繁琐步骤
方案二:通用型实现(适配非月初的起始日期)
如果你的@FromDate可能不是当月第一天,这个方案能更准确地生成区间:
DECLARE @FromDate DATE = '2023-06-01' DECLARE @ToDate DATE = '2023-08-05' ;WITH MonthStarts AS ( SELECT DATEFROMPARTS(YEAR(@FromDate), MONTH(@FromDate), 1) AS MonthStart UNION ALL SELECT DATEADD(MONTH, 1, MonthStart) FROM MonthStarts WHERE MonthStart < EOMONTH(@ToDate) ) SELECT ROW_NUMBER() OVER(ORDER BY MonthStart) AS RowNo, CASE WHEN MonthStart < @FromDate THEN @FromDate ELSE MonthStart END AS FromDate, CASE WHEN EOMONTH(MonthStart) > @ToDate THEN @ToDate ELSE EOMONTH(MonthStart) END AS ToDate, DATENAME(MONTH, MonthStart) + '-' + CAST(YEAR(MonthStart) AS VARCHAR(4)) AS YearMonth FROM MonthStarts WHERE MonthStart <= @ToDate OPTION (MAXRECURSION 0)
优势:
- 无论
@FromDate是否为当月第一天,都能正确生成第一个区间的起始日期 - 逻辑更清晰,通过生成所有涉及月份的月初日期,再分别处理每个区间的起止
内容的提问来源于stack exchange,提问作者Zoyeb Shaikh
相关产品推荐
相关产品推荐

