日期:2014-05-17  浏览次数:21070 次

用oracle 写一个函数 函数有2个参数,一个是工作日期,一个是整型表示几天。
写一个函数,要求返回当天工作日期几天后的工作日期,举例:假如今天是星期一,3天后的工作日期是星期四的工作日期。假如今天是星期五,那么3天后的工作日期是星期三的工作日期。把星期六和星期天去掉了。假如今天是星期六,3天后的工作日期就是星期三的工作日期。

------解决方案--------------------
SQL code
-- 请参考:
create or replace function fc_ncdate(i_date_id number:=to_number(to_date(sysdate-1,'YYYYMMDD')), i_ndays number:=5)
  return  tabCdate
is
/***************************************************
  **     功能:根据传入的参数i_date_id是否是工作日或非工作日
  **           (周六、日视为非工作日)来求最近N(参数i_ndays控制)个工作日或非工作日
  **   创建者:罗友谋
  ** 创建时间:2012.02.22
  ****************************************************/
  Result tabcdate := tabcdate();
  v_ndays number(18,0);
  v_is_weekday1 number(1,0); -- 标记传入的参数 是否是周六、日
  v_is_weekday2 number(1,0); -- 标记循环过程中的日期变量是否是周六、日
  v_date_id DATE;
  v_loops number(18,0);
begin
  SELECT decode(to_char(to_date(i_date_id,'YYYYMMDD'),'d'),'1',1,'7',1,0) as is_weekday INTO v_is_weekday1 FROM dual;
  v_loops := i_ndays-1;

  Result := tabcdate();
  Result.extend;
  Result(Result.count) := CDATE(NULL);
  Result(Result.count).date_id := i_date_id;

  v_date_id := to_date(i_date_id,'YYYYMMDD')-1;

  WHILE v_loops > 0 LOOP
    SELECT decode(to_char(v_date_id,'d'),'1',1,'7',1,0) as is_weekday INTO v_is_weekday2 FROM dual;
    IF v_is_weekday1<>v_is_weekday2 THEN
      v_date_id := v_date_id-1;
    ELSE
    BEGIN
      Result.extend;
      Result(Result.count) := CDATE(NULL);
      Result(Result.count).date_id := to_number(to_char(v_date_id,'YYYYMMDD'));
      v_loops := v_loops - 1;
      v_date_id := v_date_id-1;
    END;
    END IF;
  END LOOP; 

  return(Result);
end fc_ncdate;

------解决方案--------------------
SQL code
create or replace function fc_nworkday(
  i_date date:=TRUNC(SYSDATE),  -- 你要输入的日期,默认值为当天0点
  i_ndays number:=1             -- 你要查询N个工作日后的日期,N默认值为1
)
  return  date
is
/***************************************************
  **     功能:根据传入的参数i_date来求N(参数i_ndays控制)个工作日后的日期
  **   创建者:罗友谋
  ** 创建时间:2012.02.22
  ****************************************************/
  v_loops number(18,0);
  v_date DATE;
begin
  v_loops := TRUNC(i_ndays); -- 截断 i_ndays 参数的小数部分
  v_date := i_date;
  IF i_ndays >0 THEN -- 如果输入的i_ndays为正数
  BEGIN
    WHILE v_loops > 0 LOOP
      IF TO_CHAR(v_date,'d') IN ('6') THEN -- 如果是星期五
        v_date := v_date + 3;
      ELSE
        v_date := v_date + 1;
      END IF;
        v_loops := v_loops - 1;  
    END LOOP;
  END;
  ELSIF i_ndays = 0 THEN
    v_date := i_date;
  ELSE
  BEGIN
    WHILE v_loops < 0 LOOP
      IF TO_CHAR(v_date,'d') IN ('2') THEN -- 如果是星期一
        v_date := v_date - 3;
      ELSE
        v_date := v_date - 1;
      END IF;
        v_loops := v_loops + 1;  
    END LOOP;
  END;
  END IF;

  RETURN v_date;
EXCEPTION
  WHEN OTHERS THEN
    NULL;
END;
/


select to_char(fc_nworkday(sysdate,2),'YYYY-MM-DD HH24:MI:SS')
 from dual;

------解决方案--------------------
SQL code

create or replace function get_work_date(i_date_in  in date,
                                         i_date_cal in number) return date is
  flag        boolean;
  cal_day     number := abs(i_date_cal) + 1;
  add_flag    number;
  return_date date := i_date_in;
  --today_excp exception;
begin
  flag := true;
  if i_date_cal > 0 then
    add_flag := 1;
  else
    add_flag := -1;
  end if;
  if cal_day = 0 then
    flag := false;
  else
    while flag loop
      if to_char(return_date + add_flag, 'd') in ('0', '7') then
        return_date := return_date + add_flag;
      else
        return_date := return_date + add_flag;
        cal_day     := cal_day - 1;
        if cal_day <= 0 then
          flag := false;
        end if;
      end if;
    end loop;
  end if;
  return return_date;
end;

------解决方案--------------------
罗大师代码在修正一下,就可以包括周6,周天情况了