获取最近5个工作日并排除假期列表Oracle DB

时间:2017-08-17 08:06:32

标签: oracle plsql oracle11g

我创建了函数以获取最近5个工作日。它将显示该计划的当月的最后一个第5天。

我创建了一个包含假期列表的表。你能帮我修改一下这个功能吗?我尝试了如下函数,

查询后插入

AND NOT EXISTS (SELECT 1 FROM T_FACT_JOB_HOLIDAY_LIST WHERE HDLY_DATE = end_date)

主要查询:

CREATE OR replace FUNCTION test.Func_to_get_last_n_busi_days ( 
p_curr_date IN DATE, 
p_days_cnt  IN NUMBER) 
RETURN DATE 
IS 
  v_curr_date      DATE := Trunc(p_curr_date); 
  v_days_cnt       NUMBER := p_days_cnt; 
  v_month_end_date DATE; 
  v_sche_date      DATE; 
BEGIN 
    v_month_end_date := Last_day(v_curr_date); 

    IF v_month_end_date = v_curr_date THEN 
      v_month_end_date := Last_day(v_curr_date + 1); 
    END IF; 

    SELECT Min(last_n_days) 
    INTO   v_sche_date 
    FROM   (SELECT last_n_days 
            FROM   (SELECT ROWNUM rw, 
                           end_date - LEVEL + 1 last_n_days 
                    FROM   (SELECT Add_months(( v_month_end_date + 1 ), -1) AS 
                                   start_date, 
                                   v_month_end_date                         AS 
                                   end_date 
                            FROM   dual) 
                    WHERE  To_char(end_date - LEVEL + 1, 'DY') NOT IN 
                           ( 'SAT', 'SUN' ) 
                    CONNECT BY LEVEL <= ( end_date - start_date ) + 1) 
            WHERE  rw <= v_days_cnt) 
    WHERE  last_n_days > v_curr_date; 

    RETURN Trunc(v_sche_date); 
EXCEPTION 
  WHEN OTHERS THEN 
             Raise_application_error(-20010, SQLERRM); 
END; 

/  

2 个答案:

答案 0 :(得分:1)

你可以像这样生成v_month_end_date到v_curr_date的日期列表:

  select v_month_end_date - level  + 1 as d
  from dual
  connect by v_month_end_date - v_curr_date >= level -1

然后您可以按照以下方式过滤工作日和假日的日期:

select  d 
from 
(
      select v_month_end_date - level  + 1 as d
      from dual
      connect by v_month_end_date - v_curr_date >= level -1
)
where To_char(d, 'DY', 'NLS_DATE_LANGUAGE = american') NOT IN ( 'SAT', 'SUN' ) 
and NOT EXISTS (SELECT 1 FROM T_FACT_JOB_HOLIDAY_LIST WHERE HDLY_DATE = d)
order by d desc

在下一步中,您只过滤所需的商务天数并选择最短日期

select min(d)
into v_sche_date 
FROM
(
  SELECT d
  from
  (
    select rownum rn, d 
    from
    (
        select  d 
        from 
        (
              select v_month_end_date - level  + 1 as d
              from dual
              connect by v_month_end_date - v_curr_date >= level -1
        )
        where To_char(d, 'DY', 'NLS_DATE_LANGUAGE = american') NOT IN ( 'SAT', 'SUN' ) 
        and NOT EXISTS (SELECT 1 FROM T_FACT_JOB_HOLIDAY_LIST WHERE TRUNC(HDLY_DATE, 'DD') = d)
        order by d desc
    )
  )
  where 
   rn <= v_days_cnt
) 

答案 1 :(得分:0)

你试过了:

... AND NOT EXISTS (SELECT 1 FROM T_FACT_JOB_HOLIDAY_LIST 
                     WHERE HDLY_DATE = end_date)

你应该尝试(第28行):

... AND NOT EXISTS (SELECT 1 FROM T_FACT_JOB_HOLIDAY_LIST 
                      WHERE HDLY_DATE = end_date - LEVEL + 1)

但也许这个功能有点难以理解。你也可以做这个简单的循环:

create or replace function get_business_day (p_curr_date in date, p_days_cnt in number ) 
    return date is

    v_date date := last_day(p_curr_date);
    i number := 0;
    v_tmp number;
begin
    while i < p_days_cnt loop
        v_date := v_date - 1;
        begin 
            select 1 into v_tmp from t_fact_job_holiday_list where hdly_date = v_date;
        exception when no_data_found then
            i := i + 1;
        end;
    end loop;
    return v_date;
end;