2017-08-28 77 views
0

我想了解下一個工作日排除SAT,SUN和假期。我收到如下錯誤的輸出。下一個工作日使用Oracle schdule

CREATE OR REPLACE FUNCTION FUNC_TO_GET_NEXT_BUSINESS_DAY( 
P_DATE IN DATE 
,P_ADD_NUM IN INTEGER 
) RETURN DATE AS 
-- 
V_CNT NUMBER; 
V_BUS_DAY DATE := TRUNC(P_DATE); 
-- 
BEGIN 
-- 
SELECT MAX(RNUM) 
INTO V_CNT 
FROM (SELECT ROWNUM RNUM 
FROM ALL_OBJECTS) 
WHERE ROWNUM <= P_ADD_NUM 
AND TO_CHAR(V_BUS_DAY + RNUM, 'DY') NOT IN ('SAT', 'SUN') 
AND NOT EXISTS 
(SELECT 1 
FROM HOLIDAY_LIST 
WHERE HDLY_DATE = V_BUS_DAY + RNUM); 
V_BUS_DAY := V_BUS_DAY + V_CNT; 
-- 
RETURN V_BUS_DAY; 
EXCEPTION 
    WHEN OTHERS THEN 
      Raise_application_error(-20010, SQLERRM); 
-- 
END FUNC_TO_GET_NEXT_BUSINESS_DAY; 
/

輸入:

select FUNC_TO_GET_NEXT_BUSINESS_DAY(sysdate,1)+15/24 from dual; 

輸出:

3/23/2076 3:00:00 PM 
+0

我剛剛編譯的函數,並測試了幾個日期,它正在產生正確的輸出。不知道爲什麼你在2076年得到一個約會...看看你的'HOLIDAY_LIST',以確保它是正確的。另外,我看到你命名爲HDLY_DATE專欄 - 不應該是HLDY_DATE嗎? – mathguy

+0

幾乎從來沒有任何理由添加一個異常塊像什麼時候那樣的東西。只要允許通過內部機制引發的運行時異常。 – mathguy

回答

0

我會做這樣的:

CREATE OR REPLACE FUNCTION FUNC_TO_GET_NEXT_BUSINESS_DAY(
    P_DATE IN DATE, 
    P_ADD_NUM IN INTEGER) 
RETURN DATE AS 

    TYPE Date_list IS TABLE OF DATE; 
    Holidays Date_list; 
    res DATE := TRUNC(P_DATE) + P_ADD_NUM; 

BEGIN 

    SELECT HDLY_DATE 
    BULK COLLECT INTO Holidays 
    WHERE HDLY_DATE >= res 
    FROM HOLIDAY_LIST; 

    LOOP 
     EXIT WHEN res NOT MEMBER OF Holidays AND TO_CHAR(res, 'DY', 'NLS_DATE_LANGUAGE = american') NOT IN ('SAT', 'SUN'); 
     res := res + 1; 
    END LOOP; 
    RETURN res; 
end; 
+0

在「BULK COLLECT」中使用上述功能時出現錯誤。 – Vasanth

+0

錯誤是...? –

+0

邏輯似乎不正確。假設你想添加10天。你的功能今天增加了10天,並且如果不是週末或假期,接受它作爲答案。從OP的解釋和他的代碼看來,他似乎希望從今天開始計算10 **個業務**天,這是一個不同的概念。 – mathguy

0

這是我怎麼會寫這個,主要使用PL/SQL(最小化PL/SQL和SQL之間的上下文切換)。正如在Wernfried的解決方案中,我只需要將HOLIDAY_LIST表讀入PL/SQL表,然後在PL/SQL中處理所有內容。與Wernfried的解決方案不同,此版本計算未來日期爲指定的業務天,從輸入日算起。

CREATE OR REPLACE FUNCTION FUNC_TO_GET_NEXT_BUSINESS_DAY ( 
    P_DATE IN DATE , 
    P_ADD_NUM IN INTEGER 
) RETURN DATE AS 
    v_bus_day date := trunc(P_DATE); 
    cnt   integer := P_ADD_NUM; 
    type   date_list is table of date; 
    holidays  date_list; 
begin 
    select hdly_date 
    bulk collect into holidays 
    from holiday_list 
    where hdly_date > v_bus_day; 
    while cnt > 0 
    loop 
    v_bus_day := v_bus_day + 1; 
    if to_char(v_bus_day, 'DY') not in ('SAT', 'SUN') 
     and 
     v_bus_day not member of holidays 
    then cnt := cnt - 1; 
    end if; 
    end loop; 
    return v_bus_day; 
end; 
/
+0

爲了與當前用戶會話NLS-Settings無關,您應該創建'TO_CHAR(v_bus_day,'DY','NLS_DATE_LANGUAGE = american')NOT IN('SAT','SUN')''。 –

+0

@ WernfriedDomscheit - 對,但是我們還必須考慮「週末」的定義(這不是所有國家的週六至週日)等等。我通常儘量不要成爲「比教皇更天主教徒」(即OP在這些情況下)。當然,這一點很好。 – mathguy