SQL递归CTE拆分停机记录日期范围:未生成预期行数
递归CTE生成每日停机记录的逻辑错误分析
核心错误原因:递归方向与终止条件不匹配
你的问题出在递归步长和终止条件未适配日期ID的大小关系:
- 异常记录的
Date_ID_Down=7432大于Date_ID_Up=7402,说明这条停机记录的日期范围是从更大的日期ID(更晚的实际日期)到更小的日期ID(更早的实际日期)。 - 如果你的递归CTE写死了递增步长(比如
Current_Date_ID + 1)或错误的终止条件(比如Current_Date_ID < Date_ID_Up),会导致递归仅执行1次就触发终止,最终只生成锚点行(7432)和1次递归行,共2行。
常见的具体错误场景
终止条件比较方向错误
若递归成员的终止条件写为Current_Date_ID < Date_ID_Up,对于Date_ID_Down=7432、Date_ID_Up=7402的记录:- 锚点行的
Current_Date_ID=7432,第一次递归后得到7431,此时判断7431 < 7402不成立,递归直接停止,仅生成2行。
- 锚点行的
递归步长符号错误
若递归成员写死了递增步长(Current_Date_ID + 1),对于上述反向范围的记录,每次递归会离目标7402越来越远,终止条件快速触发,同样只生成少量行。
修正方案:统一处理日期范围的正向递归
先统一每条记录的起止日期顺序,再按固定方向递归,避免因日期ID大小反转导致的错误:
WITH RecursiveCTE AS ( -- 锚点成员:统一起止日期,取最小ID为起始,最大ID为结束 SELECT CASE WHEN Date_ID_Down <= Date_ID_Up THEN Date_ID_Down ELSE Date_ID_Up END AS CurrentDateID, CASE WHEN Date_ID_Down <= Date_ID_Up THEN Date_ID_Down ELSE Date_ID_Up END AS New_Down, CASE WHEN Date_ID_Down <= Date_ID_Up THEN Date_ID_Down ELSE Date_ID_Up END AS New_Up, -- 保留原始起止ID用于后续逻辑(可选) Date_ID_Down AS Original_Down, Date_ID_Up AS Original_Up, -- 其他需要保留的字段 * FROM @DowntimeFact UNION ALL -- 递归成员:按递增方向生成每日记录 SELECT CurrentDateID + 1 AS CurrentDateID, CurrentDateID + 1 AS New_Down, CurrentDateID + 1 AS New_Up, Original_Down, Original_Up, -- 其他字段 r.* FROM RecursiveCTE r -- 终止条件:当前日期ID未达到最大的结束ID WHERE CurrentDateID < CASE WHEN r.Original_Down <= r.Original_Up THEN r.Original_Up ELSE r.Original_Down END ) -- 最终查询:输出每日的停机记录 SELECT New_Down, New_Up, -- 其他需要的字段 FROM RecursiveCTE ORDER BY Original_Down, Original_Up, CurrentDateID;
这个方案会自动适配Date_ID_Down大于或小于Date_ID_Up的情况,确保每条记录都能生成完整的每日行。
内容的提问来源于stack exchange,提问作者Danie Schoeman
相关产品推荐
相关产品推荐

