T-SQL获得2个日期之间的工作日数

Roc*_*shy 4 sql t-sql sql-server

我想计算两个给定日期之间的工作日数.例如,如果我想计算2013-01-10和2013-01-15之间的工作日,结果必须是3个工作日(我没有考虑该间隔的最后一天,我减去星期六和周日).我有以下代码适用于大多数情况,除了我的示例中的一个.

  SELECT (DATEDIFF(day, '2013-01-10', '2013-01-15')) 
    - (CASE WHEN DATENAME(weekday, '2013-01-10') = 'Sunday' THEN 1 ELSE 0 END)
    - (CASE WHEN DATENAME(weekday, DATEADD(day, -1, '2013-01-15')) = 'Saturday' THEN 1 ELSE 0 END)
Run Code Online (Sandbox Code Playgroud)

我怎么能做到这一点?我是否必须经历所有的日子并检查它们?或者有一个简单的方法来做到这一点.

Aar*_*and 16

请,请使用日历表.SQL Server对国家法定假日,公司事件,自然灾害等一无所知.日历表相当容易构建,占用的空间极小,如果足够引用,它将在内存中.

下面是一个创建具有30年日期(2000 - > 2029)的日历表的示例,但磁盘上只需要200 KB(如果使用页面压缩则为136 KB).这几乎可以保证小于在运行时处理某些CTE或其他集所需的内存授权.

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.
Run Code Online (Sandbox Code Playgroud)

现在你要查询的查询非常简单:

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

有关日历表的更多信息:

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

有关无循环生成集的更多信息:

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

还要注意依赖英语输出的小事DATENAME.我见过几个应用程序中断,因为有些用户使用不同的语言设置,如果你依赖,请WEEKDAY确保你DATEFIRST设置得恰当...