0

我正在處理的情況是,我有一個優先級列表與特定數量的工作日相關聯。TSQL - 增加營業日至日期,不包括節假日

例如,如果我今天的日期爲2017-01-26,需要增加5個工作日,則它將返回2017-02-02

要混合一些附加功能,我有一張公司定義的假期表,它需要排除。如果我從2017-02-16中選擇5工作日,則會看到美國總統日落在2017-02-20之後,並且會跳過該步驟,從而使5th工作日2017-02-24

我發現了另一個這樣的例子,我試圖去適應我的需求。問題是,我不完全知道發生了什麼,只是我的增加不會導致我期望的結果。

基準柱:https://stackoverflow.com/a/12862675/2628921

ALTER FUNCTION [dbo].[findBusinessDayAfter] 
(@date DATETIME, @days INT) 
RETURNS DATE 
AS 
BEGIN 
    RETURN (SELECT thedate 
      FROM (SELECT dateadd(d, v.day, CAST (@date AS DATE)) AS thedate, 
          row_number() OVER (ORDER BY v.day) AS rn 
        FROM (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), (31), (32), (33), (34), (35), (36), (37), (38), (39), (40)) AS v(day) 
          LEFT OUTER JOIN 
          holidays AS h 
          ON h.holidayDate = dateadd(d, v.day, CAST (@date AS DATE)) 
        WHERE h.holidayDate IS NULL 
          AND LEFT(datename(dw, dateadd(d, v.day, CAST (@date AS DATE))), 1) <> 'S') AS x 
      WHERE @days = rn); 
END 

在給出的原始實例中,他們使用的是(1) - (10)。但是,我有些情況下需要將35-40個工作日添加到日期,因此我相應地調整了查詢​​以允許我進入該日期。

我發現,當我嘗試運行某些日期與工作日,它返回一個null值,我不知道爲什麼。

-- Multiple Holidays (Day before Thanksgiving) 
SELECT dbo.findBusinessDayAfter('2017-11-05', 35) -- Returns NULL 

我並不確切知道什麼是在原代碼段會阻止我能夠增加它們的默認10 days30+天發生。

有關如何調整以適應我的用例的想法?

+2

爲什麼不創建日曆表並做這樣的事情? HTTPS://www.mssqltips。COM/sqlservertip/4054 /創建-A-日期維度或日曆表,在-SQL服務器/ – dadde

回答

0

我試圖這樣做,運行你的SP內部:

DECLARE @holidays TABLE(holidayDate DATE); 
INSERT INTO @holidays 
     SELECT * 
     FROM(VALUES('20170103')) f(b); 
DECLARE @date DATETIME= '20170101', @days INT= 1; 

我再運行內部select語句

SELECT DATEADD(d, v.day, CAST(@date AS DATE)) AS thedate, 
     ROW_NUMBER() OVER(ORDER BY v.day) AS rn 
FROM(VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), (31), (32), (33), (34), (35), (36), (37), (38), (39), (40)) AS v(day) 
    LEFT OUTER JOIN @holidays AS h ON h.holidayDate = DATEADD(d, v.day, CAST(@date AS DATE)) 
WHERE h.holidayDate IS NULL 
     AND LEFT(DATENAME(dw, DATEADD(d, v.day, CAST(@date AS DATE))), 1) <> 'S' 

此列出天是工作日,從提供的日期,並在@日期+ 45天的最接近日曆日的營業日結束。 所有節假日和週末都從列表中刪除。根據我輸入的價值,自2017年1月1日至2月15日(即1月1日之後的45個日曆日)將有29個工作日。因此,這是您的問題,您想要在35個工作日內完成工作,但根本不是那樣在接下來的45個日曆日內有許多工作日。

我希望這可以清楚說明你的代碼中發生了什麼,以及它爲什麼會失敗。 現在快速解決方案是展望更多日曆日。 在這裏我過你的45每日可加入3倍,從1到45×45×45-1領先天

SELECT DATEADD(d, v1.day+45*(v2.day-1)+45*45*(v3.day-1), CAST(@date AS DATE)) AS thedate, 
      ROW_NUMBER() OVER(ORDER BY v1.day+45*(v2.day-1)+45*45*(v3.day-1)) AS rn 
    FROM 
     (VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), (31), (32), (33), (34), (35), (36), (37), (38), (39), (40)) AS v1(day) 
cross join  
     (VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), (31), (32), (33), (34), (35), (36), (37), (38), (39), (40)) AS v2(day) 
cross join  
     (VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), (31), (32), (33), (34), (35), (36), (37), (38), (39), (40)) AS v3(day) 
     LEFT OUTER JOIN @holidays AS h ON h.holidayDate = DATEADD(d, v1.day+45*(v2.day-1)+45*45*(v3.day-1), CAST(@date AS DATE)) 
    WHERE h.holidayDate IS NULL 
      AND LEFT(DATENAME(dw, DATEADD(d, v1.day+45*(v2.day-1)+45*45*(v3.day-1), CAST(@date AS DATE))), 1) <> 'S' 

這給你提前去幾千天的可能性計算運行總和。它可能不是最優雅的解決方案,但它應該可以解決您的問題。