代码之家  ›  专栏  ›  技术社区  ›  Simon Mark Smith

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

  •  1
  • Simon Mark Smith  · 技术社区  · 15 年前

    我意识到不同的解决方案会有不同的“工作日”的含义,但在我的例子中,我的意思是星期一到星期五。

    基本上,我已经创建了一个函数来为我进行计算,并且我当前的解决方案是有效的。我的担心(和问这个问题的原因)是我担心这是一个实现这一点的糟糕方法,因为函数被调用的频率非常高。在过去的3个月里,生产系统的平均工作时间为44ms,被称为1200万次。

    这让我怀疑这是否是实现解决方案的正确方法。

    首先是我创建的函数:

     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 回复  |  直到 15 年前
        1
  •  2
  •   AdaTheDev    15 年前

    我不认为在UDF tbh中可以做很多事情——在运行时像SQL中这样计算它总是会在某种程度上受到影响。

    所以,理想情况下(这可能是不可能的,因为我不知道完整的图片),我想我要做的是将工作日数存储在您的表中,并在创建记录时计算一次。如果这是不可能的(即当创建记录时,您没有“结束日期”,因此必须使用“现在”来计算),那么我将考虑一个夜间计划的作业,去重新计算所有这些特定记录,以便每天更新它们-然后当输入“结束日期”时,该记录不会包含在BATC中。h更新。

    这样做的好处是,您将计算卸载到一个更安静的阶段,并且每天只进行一次计算。查询变得更简单,性能也更高,因为它可以从表中读取工作日数。

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

        2
  •  0
  •   duffymo    15 年前

    这里有两个问题:

    1. 计算两个日期之间的天数,
    2. 确定给定日期是否为“工作日”。

    第二类包括“工作日”与“周末”、节日(世俗、宗教和法律)等简单的节日。

    你需要解决这两个问题。

    第一个更简单,因为关系数据库将具有帮助您的功能。这是第二个更难、更变化多端的问题,因为它会随着地区和业务的变化而变化。