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://www.sqlperformance.com/tag/date-ranges
还要注意依赖英语输出的小事DATENAME.我见过几个应用程序中断,因为有些用户使用不同的语言设置,如果你依赖,请WEEKDAY确保你DATEFIRST设置得恰当...
| 归档时间: |
|
| 查看次数: |
20682 次 |
| 最近记录: |