[SQL]計算日期之間的工作日

要計算2個日期之間的工作日,SQL要如何寫呢?

一般要計算2個日期之間的工作日是將這2個日期之間的星期六、日及節日扣掉之後,就是剩下的就是工作日。

以 2015/05/01 到 2015/05/08 為例,

05/01 到 05/08 為 8 天

05/01 為 勞動節

05/02, 05/03 為星期六、日

所以工作天數為 5天 (8 - 1 - 2),  2015/5/4 ~ 2015/5/8

那SQL要如何算呢?


--資料準備 
/* 
--假日檔
CREATE TABLE Holidays
(
Id INT IDENTITY,
HolidayDate DATE,
HolidayName NVARCHAR(32) 
)
GO

INSERT INTO dbo.Holidays
        (HolidayDate, HolidayName )
VALUES  ('2015/05/01', N'勞動節');

INSERT INTO dbo.Holidays
        (HolidayDate, HolidayName )
VALUES  ('2015/05/20', N'其他節');

*/


DECLARE @startDate  DATETIME, @endDate DATETIME
SELECT @startDate = '2015/05/01'  -- 開始日期
,@endDate = '2015/05/08' -- 結束日期
 
--05/01 到 05/08 為 8 天
;WITH DaysRange -- 所有日期
AS(
	SELECT @startDate AS WorkDay, DATEDIFF(DAY, @startDate, @endDate) AS DiffDays
	UNION ALL
	SELECT DATEADD(dd, 1, WorkDay),DiffDays -1
	FROM DaysRange wd
	WHERE DiffDays > 0
)
SELECT * 
FROM DaysRange;

--05/01 為 勞動節
SELECT *
FROM dbo.Holidays
WHERE HolidayDate >= @startDate 
AND HolidayDate <= @endDate;

--05/02, 05/03 為星期六、日
;WITH Days67 -- 星期六、日
AS(
	SELECT @startDate AS WorkDay, DATEDIFF(DAY, @startDate, @endDate) AS DiffDays
	UNION ALL
	SELECT DATEADD(dd, 1, WorkDay),DiffDays -1
	FROM Days67 wd
	WHERE DiffDays > 0
)
SELECT * 
FROM Days67
WHERE DATEPART(dw, WorkDay ) IN (1, 7);

image

 

所以將它們組合起來如下,


-- *** 組合起來 ***
DECLARE @startDate  DATETIME, @endDate DATETIME
SELECT @startDate = '2015/05/01'  -- 開始日期
,@endDate = '2015/05/08' -- 結束日期
 
--05/01 到 05/08 為 8 天
;WITH WorkDays -- 所有日期 扣掉 6、日及節日
AS(
	SELECT @startDate AS WorkDay, DATEDIFF(DAY, @startDate, @endDate) AS DiffDays
	UNION ALL
	SELECT DATEADD(dd, 1, WorkDay),DiffDays -1
	FROM WorkDays wd
	WHERE DiffDays > 0

)
SELECT * 
FROM WorkDays wd
WHERE DATEPART(dw, WorkDay ) IN (2,3, 4, 5, 6) -- 星期 1 ~ 5
AND NOT EXISTS (SELECT * FROM dbo.Holidays h WHERE h.HolidayDate = wd.WorkDay); -- 非節日

image

 

參考資料

透過common table expressions (CTE)來產生某區間的連續序號

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^