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

解决方案 »

  1.   


    create table t1 (c1 date);insert into t1 values (date'2012-05-25');
    insert into t1 values (date'2012-05-28');
    insert into t1 values (date'2012-05-31');
    insert into t1 values (date'2012-06-01');
    commit;select c1,
           case when to_char(c1,'d') <= 2 then c1+3
                when to_char(c1,'d') > 2 and to_char(c1,'d') < 6 then c1 + 5
                else c1+4 
           end c2
    from t1      c1        c2
    ----------------------------------------
    1 2012/5/25 2012/5/29
    2 2012/5/28 2012/5/31
    3 2012/5/31 2012/6/5
    4 2012/6/1 2012/6/5
      

  2.   

    -- 请参考:
    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;
      

  3.   

    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;
      

  4.   

    -- 建议:尽量不要在函数中用 connect by 递归,这样会影响你在SQL语句中调用函数的执行效率!
      

  5.   


    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.   

    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 i_date_cal = 0 then
        flag := false;
        if to_char(return_date, 'd') in ('1') then
          return_date := return_date + 1;
        elsif to_char(return_date, 'd') in ('7') then
          return_date := return_date + 2;
        end if;
      end if;
      while flag loop
        if to_char(return_date + add_flag, 'd') in ('1', '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;
      return return_date;
    end;
      

  7.   

    罗大师代码在修正一下,就可以包括周6,周天情况了
    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;
          ELSIF TO_CHAR(v_date,'d') IN ('7') THEN -- 如果是星期6
            v_date := v_date + 2;
                ELSIF TO_CHAR(v_date,'d') IN ('1') THEN -- 如果是星期天
            v_date := v_date + 1;
             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;
          ELSIF TO_CHAR(v_date,'d') IN ('1') THEN -- 如果是星期天
            v_date := v_date - 2;
           ELSIF TO_CHAR(v_date,'d') IN ('7') THEN -- 如果是星期6
            v_date := v_date - 1;  
          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;
    /