使用Oracle schdule获取下n个工作日

时间:2017-08-28 09:10:37

标签: oracle oracle11g

我试图找出下一个工作日排除SAT,SUN和Holidays。我得到错误的输出如下。

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; 
/ 

INPUT:

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

输出:

3/23/2076 3:00:00 PM

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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;
/