基于tbl_Shift表计算指定日期工作日:SQL查询结果异常求助
解决指定时间段工作日计算错误的问题
咱们先拆解下你的问题:现有查询返回26天,但实际2018年5月31天、每周2个休息日(周六+周日),正确工作日应该是23天。问题出在你的查询逻辑没有准确统计出时间段内所有的休息日数量,咱们一步步修正:
原查询的核心问题
你的现有代码用总天数减去周数(默认每周扣1天),再加1次第二个休息日的扣除,这完全没考虑到5月实际有多少个周六和周日——2018年5月有4个周六、4个周日,总共8个休息日,31-8=23才是正确结果。
正确的解决方案
我们需要先生成指定日期范围内的每一天,再逐一判断该日期是否属于tbl_Shift定义的休息日,最后统计非休息日的数量。这里用CTE递归生成日期序列:
DECLARE @StartDate DATETIME DECLARE @EndDate DATETIME SET @StartDate = '2018/05/01' SET @EndDate = '2018/05/31' WITH DateRange AS ( -- 初始化起始日期 SELECT @StartDate AS DateVal UNION ALL -- 递归生成后续所有日期 SELECT DATEADD(dd, 1, DateVal) FROM DateRange WHERE DateVal < @EndDate ) SELECT COUNT(*) AS TotalWorkDays FROM DateRange d -- 关联休息日配置表 CROSS JOIN HRM.tbl_Shift s WHERE -- 判断当前日期的星期名称不在休息日列表中 DATENAME(WEEKDAY, d.DateVal) NOT IN ( s.OffDay1, -- 仅当启用第二个休息日时,才将其纳入判断 CASE WHEN s.IsAlternateOffDay2 = 1 THEN s.OffDay2 ELSE NULL END ) -- 递归默认上限100层,开启最大递归支持整月日期生成 OPTION (MAXRECURSION 0);
额外注意点
- 如果你的数据库语言是中文,
DATENAME(WEEKDAY, ...)会返回“星期日”这类中文名称,需要确保tbl_Shift里的OffDay1/OffDay2存储的名称和它一致;或者改用DATEPART(WEEKDAY, ...)匹配数字(比如周日=1、周六=7,注意数据库SET DATEFIRST的设置)。 - 这个方法的优势是灵活适配任何休息日规则,哪怕后续调整休息日配置,查询逻辑不需要大改。
内容的提问来源于stack exchange,提问作者Doonie Darkoo




