我想计算两个给定日期之间的工作日数。例如,如果我想计算 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)
我怎样才能做到这一点?我必须把所有的日子都过一遍并检查它们吗?或者有没有一种简单的方法可以做到这一点。
最佳答案
请,请,请使用日历表。 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.
现在您要编写的查询非常简单:
SELECT COUNT(*) FROM dbo.Calendar
WHERE dt >= '20130110'
AND dt < '20130115'
AND IsWorkDay = 1;
有关日历表的更多信息:
有关无循环生成集的更多信息:
http://www.sqlperformance.com/tag/date-ranges
还要注意一些小事情,例如依赖 DATENAME
的英文输出。我见过几个应用程序因某些用户的语言设置不同而崩溃,如果您依赖 WEEKDAY
,请确保正确设置 DATEFIRST
设置...
关于sql - T-SQL获取2个日期之间的工作日数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14749877/