如果有開始日期,再給你一個工作天數,是否可以找出這些工作日呢?
如果有開始日期,再給你一個工作天數,是否可以找出這些工作日呢?
我們可以依「計算日期之間的工作日」的方式,將工作天數再加上節日及星期六、日。
以開始日期為 2015/05/01 ,工作天數為 5 天
05/01 為 勞動節
05/02, 05/03 為星期六、日
所以要加上 3 天
就會是 2015/05/01 ~ 2015/05/08
這樣子就可以了嗎???
如果 2015/05/08 是節日的話,那天數還要再加 1 天。
可是,前面我頂多只會先算到 2015/05/01 ~ 2015/05/05 之間的假日。
所以還要再看前面多出來的天數加進去後,再看有沒有假日,然後再加,再Check,再加 ..... 一直下去
我們可以用另一個做法,就是多取幾天出來,找出工作日,然後再依天數來取得那些工作日。
把邏輯列清楚後,我們就可以開始來寫SQL了,如下,
以開始日期為 2015/05/01 ,工作天數為 5 天
05/01 為 勞動節
05/02, 05/03 為星期六、日
05/08 為 臨時節日
所以工作日會是 5/4 ~ 5/7 及 5/11
/* 資料準備
--假日檔
-- Drop TABLE Holidays;
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/08', N'臨時節日');
*/
DECLARE @startDate DATETIME,
@workDays INT, @bufferDays INT;
SELECT @startDate = '2015/05/1' -- 開始日期
,@workDays = 5 -- 工作天數為 5
,@bufferDays = 30 -- 計算後面的 Buffer 的天數
;WITH WorkDays -- 所有日期
AS(
SELECT @startDate AS WorkDay, @workDays + @bufferDays AS DiffDays
UNION ALL
SELECT DATEADD(dd, 1, WorkDay),DiffDays -1
FROM WorkDays wd
WHERE DiffDays > 1
), HoldaysRange --星期 六 日及節日
AS (
SELECT *
FROM WorkDays wds
WHERE DATEPART(dw, wds.WorkDay ) IN (1, 7)
OR EXISTS (SELECT * FROM dbo.Holidays h WHERE h.HolidayDate = wds.WorkDay)
), WorkDaysRange
AS (
SELECT wd.*, ROW_NUMBER() OVER(ORDER BY wd.WorkDay) AS seq
FROM WorkDays wd
LEFT JOIN HoldaysRange hr
ON wd.WorkDay = hr.WorkDay
WHERE hr.WorkDay IS NULL
)
SELECT *
FROM WorkDaysRange wr
WHERE wr.seq <= @workDays
OPTION (MAXRECURSION 0);
WorkDays : 為 開始日期(@startDate) 到 工作天數(@workDays) + 預加的工作天數(@bufferDays) 之間的日期。
HoldaysRange : 為 WorkDays 之間的所有假日(星期 六 日及節日)
所以 WorkDays 與 HoldaysRange LEFT JOIN 找出工作日,再加上流水號(seq)。
再用原本要的天數跟那個流水號比較就可以找出我們需要的工作日。
參考資料
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^