CTE查询返回不同结果的问题咨询(CTE入门阶段)
解决思路与完整代码实现
嘿,我太懂刚接触CTE时那种摸不清门路的感觉了,咱们一步步拆解你的问题,把代码补全并跑通~
首先先把你提供的表结构和测试数据用标准SQL代码块整理出来:
create table tblHolidays ( HolidayId int identity(101, 1) Primary Key, HolidayDate datetime ) go insert into tblHolidays values ('2015-01-10'), ('2015-01-09'), ('2015-01-08'), ('2015-01-07'), ('2015-02-19'), ('2015-03-11'), ('2015-04-11') go
从你的描述来看,你想获取第一个非假日的前一天——结合你的假日数据,其实就是找最早的连续假日段的最后一天(比如2015-01-07到01-10是连续4天假日,之后的2015-01-11是非假日,它的前一天就是2015-01-10)。下面用CTE来实现这个需求:
WITH CTE_Ranked AS ( -- 第一步:给假日日期按升序排序,生成连续分组的标识 SELECT HolidayDate, -- 连续的日期会生成相同的GroupKey,这是分组的关键 DATEADD(DAY, -ROW_NUMBER() OVER(ORDER BY HolidayDate), HolidayDate) AS GroupKey FROM tblHolidays ), CTE_ContinuousGroups AS ( -- 第二步:按GroupKey分组,得到每个连续假日段的起止日期 SELECT MIN(HolidayDate) AS StartHoliday, MAX(HolidayDate) AS EndHoliday, COUNT(*) AS HolidayCount FROM CTE_Ranked GROUP BY GroupKey ) -- 第三步:取最早的连续假日段的结束日期,就是第一个非假日的前一天 SELECT TOP 1 EndHoliday AS FirstNonHolidayPrevDay FROM CTE_ContinuousGroups ORDER BY StartHoliday ASC;
代码逻辑拆解
- CTE_Ranked:通过
ROW_NUMBER()给假日日期排序,再用HolidayDate - 排序序号生成分组键。连续的日期会得到相同的GroupKey(比如2015-01-07排第1,计算后得到2015-01-06;2015-01-08排第2,计算后也得到2015-01-06,以此类推)。 - CTE_ContinuousGroups:按
GroupKey分组,就能把连续的假日归为一组,得到每组的开始、结束日期和假日天数。 - 最后一步筛选出最早的连续假日组的结束日期,就是你要的目标值。
如果你的需求是找到所有非假日里最早的那个日期的前一天,也可以用递归CTE生成日期范围来实现:
WITH CTE_DateRange AS ( -- 递归生成从最早假日到最晚假日的所有日期 SELECT MIN(HolidayDate) AS DateVal FROM tblHolidays UNION ALL SELECT DATEADD(DAY, 1, DateVal) FROM CTE_DateRange WHERE DateVal < (SELECT MAX(HolidayDate) FROM tblHolidays) ) -- 找出不在假日表中的最早日期,再往前推一天 SELECT TOP 1 DATEADD(DAY, -1, DateVal) AS FirstNonHolidayPrevDay FROM CTE_DateRange WHERE DateVal NOT IN (SELECT HolidayDate FROM tblHolidays) ORDER BY DateVal ASC;
刚上手CTE的话,记住它的核心优势就是把复杂查询拆分成多个逻辑清晰的临时结果集,比嵌套子查询可读性高太多啦~
内容的提问来源于stack exchange,提问作者MichaelB
相关产品推荐
相关产品推荐

