对于SQL datediff,不包括周末和公共假期

时间:2018-10-12 08:38:08

标签: sql sql-server

此代码有效,但似乎结果在1天后就消失了

目标:找到给定的两个日期的datediff。

但是,我们将不得不排除

  • 周末
  • 公众假期

示例

2017-11-04 00:00:00和2017-11-22 10:21:00之间的区别

  • 预期结果:12.42(3个周六和周日除外)

  • 当前结果:13.42

该代码不是我编写的,因此我正在尝试理解它。我评论了一些我也不清楚的部分。

/**This part is to find the difference in time for the two dates**/
DECLARE @temp AS DECIMAL(10,2) = CAST(DATEDIFF(hour, CONVERT(time, @StartDate), CONVERT(time, @ENDDate)) as Decimal(10,2))/24.00


Declare @numdays int=0

/**This part is to find the difference in date for the two dates**/
/**Issues likely to come from here**/
IF DATEDIFF(day,@StartDate,@ENDDate)>0 
BEGIN
    WHILE DATEDIFF(day,@StartDate,@ENDDate)>0
    BEGIN 
        SET  @StartDate=DATEADD(d,1,@StartDate) 
        WHILE exists (SELECT Holiday_Date FROM Holiday where Holiday_Date=CONVERT(date, @StartDate))  or DATENAME(DW,@StartDate)='saturday' or DATENAME(DW,@StartDate)='sunday'
            BEGIN
                SET  @StartDate=DATEADD(d,1,@StartDate)
                /**Exclude weekends and PH so we do not add numDays here **/
            END
        SET @numDays=@numDays+1
    END
END

/**Omitted some irrelevant codes here**/

/**Add both differences together to get final result**/
DECLARE @result AS DECIMAL(10,2) = @temp + @numDays

RETURN @result

正在考虑只纠正逻辑而不是重写整个代码。谢谢!

3 个答案:

答案 0 :(得分:2)

就像已经提到的,最好的方法是创建一个Calendar Table,然后使用“工作日”列或您所谓的“工作日”列来计算差异。

这是伪SQL,没有有效的日历表,但应该可以帮助您:

SELECT YT.{YourColumn},
       WD.WorkingDays
FROM YourTable YT
     CROSS APPLY (SELECT COUNT(CT.DateKeyColumn) -1 AS WorkingDays --Minus 1, as we don't want to include the first day
                  FROM CalendarTable CT
                  WHERE CT.[DateColumn] >= YT.StartingDateColumn
                    AND CT.[DateColumn] <= YT.EndingDateColumn
                    AND CT.WorkingDay = 1) WD

答案 1 :(得分:1)

您提到的代码基本上在伪代码中执行以下操作:

while i between @StartDate and @ENDDate
begin
    increment i by 1
    increment i until it is not a holiday
    add one day to result
end
return result

我的看法是这段代码难看且效率低下。

  1. 它使用@StartDate作为“输入参数”,即true 开始日期,以及循环变量。这很令人困惑。
  2. 在非常特殊的情况下使用循环和游标非常有效,但这当然不是其中之一。

您遇到的麻烦中90%是创建日历表;但您已经有一个。不要使用此功能;将代码更改为Larnu的建议。如果您遇到困难,请询问我们进一步的澄清。

答案 2 :(得分:0)

在MySQL 5.1中测试: MySQL的“工作日”函数对Mon返回0,对SAT返回5,对SUN返回6,因此您在下面的SQL中看到了一些不可思议的数字。与5和6。

示例:

select  floor((datediff (ed, st)+1) / 7)*2 /*complete week's weekends*/
        + case when floor((datediff (ed, st) +1) % 7) between 0 and 6 /*additional weekends besides complete weeks*/
                then case when weekday(ed) >= weekday(st) then least(floor((datediff (ed, st) +1) % 7), greatest(least(6, weekday(ed)) - greatest(5, weekday(st)) + 1,0))
                                else least(floor((datediff (ed, st) +1) % 7), greatest(least(6, weekday(ed)+7) - greatest(5, weekday(st)) + 1,0)) end
            else 0
        end as num_of_sat_and_sun
from (select '2019-01-07' as st, '2019-01-12' as ed) x