使用Oracle Schedule获取下一个n个工作日

使用Oracle Schedule获取下一个n个工作日,oracle,oracle11g,Oracle,Oracle11g,我想知道下一个工作日不包括周六、周日和节假日。我得到了如下错误的输出 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 F

我想知道下一个工作日不包括周六、周日和节假日。我得到了如下错误的输出

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; 
/ 
输出:

3/23/2076 3:00:00 PM

我会这样做:

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;

我会这样做:

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;

下面是我将如何编写本文,主要使用PL/SQL(最小化PL/SQL和SQL之间的上下文切换)。在Wernfried的解决方案中,我只需要将HOLIDAY_列表读入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;
/

下面是我将如何编写本文,主要使用PL/SQL(最小化PL/SQL和SQL之间的上下文切换)。在Wernfried的解决方案中,我只需要将HOLIDAY_列表读入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;
/

我在“批量收集”中使用上述函数时出错。逻辑似乎不正确。假设你想增加10天。您的函数在今天的基础上增加10天,如果不是周末或假日,则接受这一结果。从OP的解释和他的代码来看,他似乎希望从今天算起提前10个工作日,这是一个不同的概念。@mathguy,很可能是的,我没有详细研究他的代码。问题中没有说明。我认为标题中的“Get next n business days”表明了这一点。我在“BULK COLLECT”中使用上述函数时出错。逻辑似乎不正确。假设你想增加10天。您的函数在今天的基础上增加10天,如果不是周末或假日,则接受这一结果。从OP的解释和他的代码来看,他似乎希望从今天算起提前10个工作日,这是一个不同的概念。@mathguy,很可能是的,我没有详细研究他的代码。问题中没有说明。我认为标题中的“Get next n business days”表明了这一点。我只是编译了函数并用几个日期进行了测试,它正在生成正确的输出。不知道你为什么要在2076年约会。。。查看您的
假日列表
,确保其正确无误。另外,我看到您将一列命名为HDLY_DATE—这不应该是HLDY_DATE吗?几乎没有理由添加一个异常块,比如当其他块出现时。只要允许运行时抛出的任何异常通过内部机制引发就行了。我刚刚编译了该函数并用一些日期进行了测试,它正在生成正确的输出。不知道你为什么要在2076年约会。。。查看您的
假日列表
,确保其正确无误。另外,我看到您将一列命名为HDLY_DATE—这不应该是HLDY_DATE吗?几乎没有理由添加一个异常块,比如当其他块出现时。只要允许运行时抛出的任何异常通过内部机制引发即可。为了独立于当前用户会话NLS设置,您应该将
设置为\u CHAR(v\u bus\u day,'DY',NLS\u DATE\u LANGUAGE=american')而不是('SAT','SUN')
。@WernfriedDomscheit-对,但是,我们也必须考虑“周末”的定义(它不是所有国家的Sun Sun),等等。我通常试着不要“比教皇更虔诚”(在这些情况下是OP)。当然,这一点是很好的。你应该使<代码> toyChar(vButhayDay','Dy,'nLSsDATEAL =美国)不在(“SAT”,“Sun”)<代码>中,以独立于当前用户会话NLS设置。@ WnnFrReDeMeScEIT——对,但是我们还必须考虑“周末”(它不是所有国家的Sun Sun)的定义,等等。我一般都尽量不“比教皇更天主教”(在这些情况下,OP就是这样)。当然,这一点是正确的。