SQL Server 2008 R2从指定日期生成跨年度逐月行记录问题
解决方案
你的原有查询问题在于仅对月份做累加,未处理月份到12后年份自动进位的逻辑,且终止条件仅判断月份未考虑年份差,因此无法生成跨年度的月份数据。
可以通过直接递增加月份的方式实现需求,SQL Server的DATEADD函数会自动处理年月的进位逻辑,无需手动判断边界,适配SQL Server 2008 R2版本的查询如下:
;WITH listOfMonth(CurrentMonth, ContractId) AS ( SELECT -- 取InsertDate所在月的第一天,避免日期天数影响后续计算 DATEADD(MONTH, DATEDIFF(MONTH, 0, InsertDate), 0) AS CurrentMonth, Id AS ContractId FROM tblContract WHERE Id = 6674 UNION ALL SELECT DATEADD(MONTH, 1, CurrentMonth) AS CurrentMonth, ContractId FROM listOfMonth -- 终止条件:当前递归的月份小于当前系统时间的月份 WHERE DATEADD(MONTH, 1, CurrentMonth) < DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) ) SELECT ROW_NUMBER() OVER(ORDER BY CurrentMonth) AS ID, DATEPART(MONTH, CurrentMonth) AS MonthNumber, ContractId, DATEPART(YEAR, CurrentMonth) AS YearNumber FROM listOfMonth -- 如果年月跨度超过100个月,需要取消递归深度限制,加上下面这行 -- OPTION (MAXRECURSION 0)
逻辑说明
- 锚点查询直接取
InsertDate所在月份的第一天作为递归起始值,避免当月日期天数(比如4月30日)对后续月份加减的影响 - 每次递归直接对日期加1个月,自动处理12月之后跳转到下一年1月的逻辑
- 终止条件判断下个月是否早于当前系统时间的当月第一天,确保生成的月份到当前月为止
- 最终查询通过
ROW_NUMBER()生成自增ID,从日期中提取年份和月份即可得到你需要的输出格式
注意事项
- 如果你原表中的起始日期字段是
StartDate而非提问中说明的InsertDate,自行替换锚点查询中的字段名即可 - 原有代码中
ContracId拼写缺失字母t,修正为标准的ContractId避免后续关联出错 - 如果需要生成的年月跨度超过100个月,需要取消注释最后一行的
OPTION (MAXRECURSION 0)解除递归深度限制
内容的提问来源于stack exchange,提问作者AminM
相关产品推荐
相关产品推荐

