无需查找表生成近12个月及天数的SQL方案咨询
你的递归CTE方案完全可行,我帮你调整来满足天数需求
首先说结论:你贴的这段递归CTE写法是SQL Server里生成连续序列的经典操作,完全兼容所有支持递归CTE的SQL Server版本(从2005年的版本开始,覆盖了几乎所有在用的环境),完美符合你「不用查找表」的要求。不过原代码只返回了月份缩写,我帮你修改成包含对应天数的版本,顺便拆解下R(N)到底是啥意思。
修改后的完整代码(满足近12个月+对应天数)
WITH R(N) AS ( SELECT 0 UNION ALL SELECT N + 1 FROM R WHERE N < 11 -- 生成0到11共12个数字,对应近12个月 ) SELECT -- 月份缩写(比如Jan、Feb) LEFT(DATENAME(MONTH, DATEADD(MONTH, -N, GETDATE())), 3) AS month_abbr, -- 完整月份名称(可选) DATENAME(MONTH, DATEADD(MONTH, -N, GETDATE())) AS month_full, -- 年份(避免跨年混淆) YEAR(DATEADD(MONTH, -N, GETDATE())) AS year, -- 当月天数 DAY(EOMONTH(DATEADD(MONTH, -N, GETDATE()))) AS days_in_month FROM R -- 按年份和月份排序,结果更直观 ORDER BY year, DATEPART(MONTH, DATEADD(MONTH, -N, GETDATE()))
如果需要兼容SQL Server 2008及更早版本(这些版本没有EOMONTH函数),把days_in_month的计算改成下面的写法即可:
DAY(DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE())))) AS days_in_month
关于R(N)的含义拆解
这个R(N)是一个递归公共表表达式(CTE),拆分来看:
R是这个CTE的自定义名称,N是它里面唯一的列名——你也可以改成别的名字比如Seq(Num),只是社区习惯上用R(N)来指代这类递归序列。- 第一行
SELECT 0是锚点成员:这是递归的起点,生成第一行数据,N=0对应「当前月份」(因为DATEADD(MONTH, -0, GETDATE())就是当前月)。 - 第二部分
SELECT N + 1 FROM R WHERE N < 11是递归成员:它会反复从R里读取上一次生成的N值,加1后生成新行,直到N不满足<11的条件。这样就生成了0,1,2,...,11这12个连续整数,正好对应「当前月往前推0到11个月」的近12个月范围。
这种递归CTE的好处就是完全动态生成序列,不需要提前创建任何表,完美适配你的需求。
内容的提问来源于stack exchange,提问作者user3240998
相关产品推荐
相关产品推荐

