SQL日期计算排除周六周日:日期减法忽略周末问题排查
SQL实现忽略周末的工作日日期减法
你当前的代码核心问题是把「减去N个工作日」当成了「自然日减N天再调整起始日」,只处理了起始日期是周末的情况,但没有在减法过程中跳过周末,所以结果不符合预期。比如2023-03-20是周一,你要减去3个工作日,需要往前数3个非周末的日期(17号周五、16号周四、15号周三),最终目标是15号,但你的代码直接减3个自然日得到17号,自然不对。
下面给出两种可行的解决方案:
方法1:循环逐天递减(适合小天数场景)
逻辑简单直观,逐天往前推,每推一天就判断是否是工作日,只有工作日才减少剩余要减的天数,直到减够指定数量:
DECLARE @InputDate DATE = '2023-03-20' DECLARE @WorkdaysToSubtract INT = 3 DECLARE @TargetDate DATE = @InputDate WHILE @WorkdaysToSubtract > 0 BEGIN SET @TargetDate = DATEADD(DAY, -1, @TargetDate) -- 判断是否为周六(7)或周日(1),注意:DATEPART(WEEKDAY)的返回值受服务器DATEFIRST设置影响,可根据实际环境调整 IF DATEPART(WEEKDAY, @TargetDate) NOT IN (1, 7) BEGIN SET @WorkdaysToSubtract = @WorkdaysToSubtract - 1 END END SELECT @TargetDate AS TargetWorkdayDate
如果你的服务器把周一设为一周第一天(SET DATEFIRST 1),那么周六是6、周日是7,需要把IN里的数值改成(6,7)。
方法2:CTE递归生成日期(适合大天数场景)
如果要减的工作日数量很大,循环效率低,可以用CTE递归生成日期范围,同时统计工作日数量,直接定位到目标日期:
DECLARE @InputDate DATE = '2023-03-20' DECLARE @WorkdaysToSubtract INT = 3 ;WITH WorkdaySequence AS ( SELECT @InputDate AS CurrentDate, 0 AS WorkdayCount UNION ALL SELECT DATEADD(DAY, -1, w.CurrentDate), -- 只有非周末日期才累加工作日计数 CASE WHEN DATEPART(WEEKDAY, DATEADD(DAY, -1, w.CurrentDate)) NOT IN (1,7) THEN w.WorkdayCount + 1 ELSE w.WorkdayCount END FROM WorkdaySequence w WHERE w.WorkdayCount < @WorkdaysToSubtract ) SELECT TOP 1 CurrentDate AS TargetWorkdayDate FROM WorkdaySequence WHERE WorkdayCount = @WorkdaysToSubtract ORDER BY CurrentDate ASC
同样要注意DATEPART(WEEKDAY)的数值对应关系,根据服务器的日期设置调整IN里的参数。
内容的提问来源于stack exchange,提问作者moor
相关产品推荐
相关产品推荐

