2010-02-13 110 views
1

我意识到不同的解决方案会有“工作日”的不同变化,但在我的情况下,我的意思是星期一至星期五(含)。计算两个日期之间有多少个工作天 - T-SQL?

基本上我已经创建了一个函数来为我和我目前的解决方案进行计算。我担心(以及提出这个问题的理由)是,我担心这是实现这个目标的一个不好的方法,因为函数被调用的频率非常高。在过去的3个月中,在生产系统上被称为1200万次,平均工人时间为44毫秒。

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

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

CREATE FUNCTION [dbo].[fn_WorkDays] 
    (
    @StartDate DATETIME, 
    @EndDate DATETIME = NULL [email protected] 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调用函数)

我的问题是我在这里错过了一些东西,我这样做,是否有利于创建一个厕所KUP表此(不过这是一个很大的日期组合)

任何想法,改进或建议,将不胜感激......

+0

看看这个答案和比较说明:http://stackoverflow.com/questions/1828948/mysql-function-to-find-the-number-of-working-days-between-two-dates/1828991 #1828991 – 2010-02-13 19:48:48

+0

是否可以添加一个额外字段(计算字段)并仅在数值更改时以天数差异更新它?我的意思是,每次获得差异有什么意义? – shahkalpesh 2010-02-13 20:02:12

+0

始终将存储日期与今天进行比较......因此必须每天更新至少一次(这是一个选项) – 2010-02-13 20:06:06

回答

2

我不认为用UDF tbh可以做很多事情 - 在运行时计算它在SQL中总是会在某种程度上产生影响。

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

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

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

+0

因为计算总是基于今天,所以我需要每天分配一个值,而不是在记录创建时(也许以及在创建记录时初始化值),但请确保良好的通话。 – 2010-02-13 20:01:12

+0

@Simon - 我怀疑是这样。但我认为值得考虑夜间更新方法。每天更新一次,可以大大提高报告绩效 - 特别是如果整天计算多次 – AdaTheDev 2010-02-13 20:05:57

0

有两个问题在这里:

  1. 计算的数量两天之间的日期,
  2. 确定给定日期是否为“营业日”。

第二类包括容易的,如“工作日”与“周末”,节假日(世俗,宗教,法律等)等

你需要同时解决。

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

+0

我的要求比这更简单,我不关心假期,基本上不包括周末....我的解决方案确实做到了这一点,我只是想确保我有在这里错过了一招,并且正在以最有效的方式执行解决方案。 – 2010-02-13 19:58:04

+0

圣诞节,新年等 - 不需要担心这些?那么这是一个更容易的问题。 – duffymo 2010-02-13 20:01:48

+0

目前还没有,我只关心我对问题的解决方案的执行情况。 – 2010-02-13 20:04:56

相关问题