关于SQL递归CTE实现时间区间内日期递增及缺失日期查找的原理咨询
拆解递归CTE生成连续日期的逻辑
嘿,我来帮你把这段递归CTE的原理掰碎了讲清楚,它生成连续日期的核心是锚点成员和递归成员的配合,咱们一步步拆解:
1. 先看变量初始化
DECLARE @StartDate DATETIME DECLARE @EndDate DATETIME SET @StartDate ='2014-03-01' SET @EndDate = GETDATE()
这部分很简单,就是定义了要生成日期的起始和结束时间,GETDATE()会取当前系统时间。
2. 递归CTE的核心:锚点成员
;WITH Dates(Date) AS ( -- 锚点成员:生成第一个日期 SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, @StartDate)) AS Date
这一行是递归的起点,它的作用是把@StartDate转换成纯日期格式(去掉时分秒):
DATEDIFF(dd, 0, @StartDate):计算从SQL默认的起始日期1900-01-01到@StartDate的天数(返回一个整数)DATEADD(dd, 0, ...):把上面得到的天数再转回日期格式,相当于把@StartDate的时间部分清零,比如如果@StartDate是2014-03-01 15:30:00,会变成2014-03-01 00:00:00
执行完这一步,Dates临时表就有了第一条记录:2014-03-01。
3. 递归成员:自动生成后续日期
UNION ALL -- 递归成员:每天加1,直到超过结束日期 SELECT DATEADD(day, 1, Date) AS Date FROM Dates WHERE Date <= @EndDate )
这部分是递归的循环逻辑,执行流程是这样的:
- 第一次递归:从
Dates的第一条记录(2014-03-01)取Date,用DATEADD(day,1,Date)生成下一天2014-03-02,然后判断2014-03-02 <= @EndDate,如果满足就把这个新日期加入Dates - 第二次递归:现在
Dates里有2014-03-01和2014-03-02,递归成员会基于最新的那条记录(2014-03-02)再加1天得到2014-03-03,同样判断是否小于等于@EndDate,满足就加入 - 这个过程会不断重复,每次都基于上一轮生成的最后一个日期加1天,直到生成的日期超过
@EndDate为止,递归就自动停止了
4. 最后一步:关联业务表找缺失日期
SELECT d.Date, r.Value FROM Dates d LEFT JOIN Times r ON d.Date = r.Date
这一步就是用生成的连续日期序列Dates左连接你的业务表Times,那些r.Value为NULL的记录,就是Times表中缺失的日期——这也是你用这段代码的核心目的~
简单总结:递归CTE就像一个自动翻页的日历,先定好第一天,然后每天自动翻一页,直到翻到结束日期为止,完美生成连续的日期序列。
内容的提问来源于stack exchange,提问作者noob5eva




