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

计算两个日期之间的工作日数-T-SQL?,sql,sql-server,performance,query-optimization,Sql,Sql Server,Performance,Query Optimization,我意识到不同的解决方案会对“工作日”的含义产生不同的影响,但就我而言,我指的是周一到周五(包括周一到周五) 基本上,我已经创建了一个函数来为我进行计算,而我当前的解决方案是有效的。我的担心(以及提出这个问题的原因)是,我担心这是一种不好的实现方法,因为调用函数的频率非常高。在过去的3个月中,它在一个生产系统上被调用了1200万次,平均工作时间为44ms 这让我怀疑这是否是实现解决方案的正确方法 首先,这里是我创建的函数: CREATE FUNCTION [dbo].[fn_WorkDays]

我意识到不同的解决方案会对“工作日”的含义产生不同的影响,但就我而言,我指的是周一到周五(包括周一到周五)

基本上,我已经创建了一个函数来为我进行计算,而我当前的解决方案是有效的。我的担心(以及提出这个问题的原因)是,我担心这是一种不好的实现方法,因为调用函数的频率非常高。在过去的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次函数调用)

我的问题是我在做这件事的过程中遗漏了一些东西,为这件事创建一个查找表是否有益(但这是很多日期的组合)


如果您有任何想法、改进或建议,我们将不胜感激。

这里有两个问题:

  • 计算两个日期之间的天数
  • 确定给定日期是否为“工作日”
  • 第二种方法包括简单的方法,如“工作日”与“周末”、假日(世俗、宗教和法律)等

    你需要同时解决这两个问题


    第一个更容易,因为关系数据库将具有帮助您的功能。第二个更难,也更可变,因为它会随着区域设置和业务的变化而变化。

    我认为UDF tbh没有什么可以做的,在SQL中这样在运行时计算它总是会受到一定程度的影响

    因此,理想情况下(这可能不可能,因为我不知道全部情况),我认为我应该将工作日数存储在表中,并在创建记录时计算一次。如果这是不可能的(即,当创建记录时,您没有“结束日期”,因此必须使用“现在”来计算),那么我会考虑安排一个夜间作业,并重新计算所有这些特定记录,以便每天更新这些记录,然后在输入“结束日期”时,该记录未包含在此批处理更新中

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


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

    看看这个答案并比较注释:您是否可以添加一个额外的字段(计算字段)并仅在值发生变化时用天内的差值进行更新?我的意思是,每次获得差异的意义是什么?总是将存储的日期与今天进行比较。。。所以每天至少要更新一次(这是一个选项)我的需求的可能副本比这简单,我不关心假期,基本上不包括周末。。。。我的解决方案确实做到了这一点,我只是想确定我错过了一个技巧,并且正在以最有效的方式执行解决方案。圣诞节、新年等等-不必担心这些?然后这是一个更容易的问题。现在不是。不,我只是关心我的问题解决方案的实现。因为计算总是基于今天,我需要每天分配一个值,而不是在创建记录时分配(或者在创建记录时初始化值?),“打得好!”西蒙——我怀疑会是这样。但我认为值得考虑每晚更新的方法。每天更新一次,可以极大地提高报告性能,特别是如果计算在一天中进行多次