T-SQL get number of working days between 2 dates

后端 未结 5 1924
青春惊慌失措
青春惊慌失措 2021-01-06 06:31

I want to calculate the number of working days between 2 given dates. For example if I want to calculate the working days between 2013-01-10 and 2013-01-15, the result must

5条回答
  •  借酒劲吻你
    2021-01-06 07:09

    Please, please, please use a calendar table. SQL Server doesn't know anything about national holidays, company events, natural disasters, etc. A calendar table is fairly easy to build, takes an extremely small amount of space, and will be in memory if it is referenced enough.

    Here is an example that creates a calendar table with 30 years of dates (2000 -> 2029) but requires only 200 KB on disk (136 KB if you use page compression). That is almost guaranteed to be less than the memory grant required to process some CTE or other set at runtime.

    CREATE TABLE dbo.Calendar
    (
      dt DATE PRIMARY KEY, -- use SMALLDATETIME if < SQL Server 2008
      IsWorkDay BIT
    );
    
    DECLARE @s DATE, @e DATE;
    SELECT @s = '2000-01-01' , @e = '2029-12-31';
    
    INSERT dbo.Calendar(dt, IsWorkDay)
      SELECT DATEADD(DAY, n-1, '2000-01-01'), 1 
      FROM
      (
        SELECT TOP (DATEDIFF(DAY, @s, @e)+1) ROW_NUMBER() 
          OVER (ORDER BY s1.[object_id])
          FROM sys.all_objects AS s1
          CROSS JOIN sys.all_objects AS s2
      ) AS x(n);
    
    SET DATEFIRST 1;
    
    -- weekends
    UPDATE dbo.Calendar SET IsWorkDay = 0 
      WHERE DATEPART(WEEKDAY, dt) IN (6,7);
    
    -- Christmas
    UPDATE dbo.Calendar SET IsWorkDay = 0 
      WHERE MONTH(dt) = 12
      AND DAY(dt) = 25
      AND IsWorkDay = 1;
    
    -- continue with other holidays, known company events, etc.
    

    Now the query you're after is quite simple to write:

    SELECT COUNT(*) FROM dbo.Calendar
      WHERE dt >= '20130110'
        AND dt <  '20130115'
        AND IsWorkDay = 1;
    

    More info on calendar tables:

    http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html

    More info on generating sets without loops:

    http://www.sqlperformance.com/tag/date-ranges

    Also beware of little things like relying on the English output of DATENAME. I've seen several applications break because some users had a different language setting, and if you're relying on WEEKDAY be sure you set your DATEFIRST setting appropriately...

提交回复
热议问题