计算2个日期之间的工作天数 - T-SQL?

时间:2010-02-13 19:42:02

标签: sql sql-server performance query-optimization

我意识到不同的解决方案会对“工作日”的含义有不同的变化,但就我而言,我的意思是周一至周五。

基本上我已经创建了一个函数来为我做计算,我当前的解决方案是有效的。我担心(以及提出这个问题的原因)是我担心这是实现这个目标的一种不好的方法,因为这个函数的调用频率非常高。在过去的3个月里,它在生产系统上被称为1200万次,平均工作时间为44ms。

这让我想知道这是否是实现解决方案的正确方法。

首先,这是我创建的功能:

 CREATE FUNCTION [dbo].[fn_WorkDays]
    (
     @StartDate DATETIME,
     @EndDate   DATETIME = NULL --@EndDate replaced by @StartDate when DEFAULTed
    )
    RETURNS INT
 AS

 BEGIN
    --===== Declare local variables
    --Temporarily holds @EndDate during date reversal
    DECLARE @Swap DATETIME

    --===== If the Start Date is null, return a NULL and exit
         IF @StartDate IS NULL
            RETURN NULL

    --===== If the End Date is null, populate with Start Date value
         -- so will have two dates (required by DATEDIFF below)
         IF @EndDate IS NULL
            SELECT @EndDate = @StartDate

    --===== Strip the time element from both dates (just to be safe) by converting
         -- to whole days and back to a date.  Usually faster than CONVERT.
         -- 0 is a date (01/01/1900 00:00:00.000)
     SELECT @StartDate = DATEADD(dd,DATEDIFF(dd,0,@StartDate),0),
            @EndDate   = DATEADD(dd,DATEDIFF(dd,0,@EndDate)  ,0)

    --===== If the inputs are in the wrong order, reverse them
         IF @StartDate > @EndDate
            SELECT @Swap      = @EndDate,
                   @EndDate   = @StartDate,
                   @StartDate = @Swap

    --===== Calculate and return the number of workdays using the
         -- input parameters.  This is the meat of the function.
         -- This is really just one formula with a couple of parts
         -- that are listed on separate lines for documentation
         -- purposes.
     RETURN (
            SELECT
          --Start with total number of days including weekends
            (DATEDIFF(dd,@StartDate,@EndDate)+1)

          --Subtact 2 days for each full weekend
           -(DATEDIFF(wk,@StartDate,@EndDate)*2)

          --If StartDate is a Sunday, Subtract 1
           -(CASE WHEN DATENAME(dw,@StartDate) = 'Sunday'
                  THEN 1
                  ELSE 0
              END)

          --If EndDate is a Saturday, Subtract 1
           -(CASE WHEN DATENAME(dw,@EndDate) = 'Saturday'
                  THEN 1
                  ELSE 0
              END)
            )
END

作为其使用的一个简单示例,我将运行此类查询:

SELECT MYTABLE.EntryDate
     ,dbo.fn_WorkDays(MYTABLE.EntryDate, getutcdate()) as WorkingDays
    FROM MYTABLE                                    

MyTable可以包含5000行,所有条目在EntryDate列中都有不同的日期(5000次调用函数)

我的问题是我在这里错过了一些我正在做的事情,为此创建一个查找表是有益的(但这是很多日期组合)

任何想法,改进或建议都将受到赞赏......

2 个答案:

答案 0 :(得分:2)

我不认为你可以用UDF做很多事情 - 在运行时计算它在SQL中总是会在某种程度上受到打击。

所以,理想情况下(这可能不可能,因为我不知道全貌),我认为我要做的是将工作日数存储在表中并在创建记录时计算它。如果那是不可能的(即创建记录时,你没有“结束日期”,所以必须使用“现在”计算出来)然后我会考虑每晚预定的工作去重新计算所有那些特定记录,以便它们每天更新 - 然后当输入“结束日期”时,该记录不会包含在此批量更新中。

这样做的好处是,您可以将计算卸载到更安静的时间段,并且每天只进行一次计算。查询变得更简单,更高效,因为它只能从表中读取WorkingDays编号。

如果这不是一个选项,那么我建议在前端进行计算,从数据库中删除命中。

答案 1 :(得分:0)

这里有两个问题:

  1. 计算两个日期之间的天数,
  2. 确定给予日期是否为“营业日”。
  3. 第二种包括“平日”与“周末”,假期(世俗,宗教和法律等)等简单的等等。

    你需要解决这两个问题。

    第一个更容易,因为关系数据库将具有帮助您的功能。这是第二个更难,更多变量,因为它会因地区和业务而变化。