0

我希望在这两个日期之间只有工作日。我知道我们对我的问题有很多解决方案,但我正在寻找一些特别适合我的例子的东西

我的 sql 查询有条件

WHERE DATE_FIELD BETWEEN '1-JAN-13' AND '31-MAR-13'
AND (DATE_FIELD1 - DATE_FIELD2) > 10

我希望在两个日期之间只获得工作日,并且我希望在计算 DATE_FIELD1 - DATE_FIELD2 期间,它只考虑工作日,不包括周末。

4

2 回答 2

1

通过截断到一周的开始日期,可以计算工作日。

确定一周的开始并从日期值中减去它以获得工作日的编号:

date_field2-trunc(date_field2,'D')

之后,可以计算日期之间的工作日数:

select 
  nvl(sum(
    case

    when 
        (
          (date_field1 + (level-1))
          -
          trunc(date_field1 + (level-1),'D')
         ) 
           > 4 then 0

      else 1
    end
  ),0)
from 
  dual 
start with 
  date_field2 > date_field1
connect by 
  level < (date_field2 - date_field1) 

并将此值合并到查询中:

with sample_table as (
  select 
    trunc(sysdate)             date_field1,
    trunc(sysdate) + level - 1 date_field2
  from dual 
  connect by level <= 20
)
select 
  to_char(date_field1, 'yyyy-mm-dd') date_field1,
  to_char(date_field2, 'yyyy-mm-dd') date_field2,
  date_field2-trunc(date_field2,'D') date_field2_week_day,
  (date_field2 - date_field1)        days_between,
  (
    select 
      nvl(sum(
        case

        when 
            (
              (date_field1 + (level-1))
              -
              trunc(date_field1 + (level-1),'D')
             ) 
               > 4 then 0

          else 1
        end
      ),0)
    from dual 
    start with date_field2 > date_field1
    connect by 
      level < (date_field2 - date_field1) 
  )                                  
                                     work_days_between 

from 
  sample_table
where 
  (
    select 
      nvl(sum(
        case

        when 
            (
              (date_field1 + (level-1))
              -
              trunc(date_field1 + (level-1),'D')
             ) 
               > 4 then 0

          else 1
        end
      ),0)
    from dual 
    start with date_field2 > date_field1
    connect by 
      level < (date_field2 - date_field1) 
  )                                  
    > 10

或制作一个函数以返回相应的天数:

create or replace function get_work_days_between(
  pDate1 in date,
  pDate2 in date
) return number deterministic parallel_enable 
as
  vResult number;
  vDate1  date;
  vDate2  date;
begin

  vDate1 := trunc(pDate1);
  vDate2 := trunc(pDate2);

  select 
    nvl(sum(
      case

      when 
      (
        (vDate1 + (level-1))
        -
        trunc(vDate1 + (level-1),'D')
      ) 
      > 4 then 0

      else 1
      end
    ),0)
  into 
    vResult
  from 
    dual 
  start with 
    vDate2 > vDate1
  connect by 
    level < (vDate2 - vDate1) 
  ;

  return vResult;

end;

并在查询中使用它:

with sample_table as (
  select 
    trunc(sysdate)             date_field1,
    trunc(sysdate) + level - 1 date_field2
  from dual 
  connect by level <= 20
)
select 
  to_char(date_field1, 'yyyy-mm-dd')              date_field1,
  to_char(date_field2, 'yyyy-mm-dd')              date_field2,
  date_field2-trunc(date_field2,'D')              date_field2_week_day,
  (date_field2 - date_field1)                     days_between,
  get_work_days_between(date_field1, date_field2) work_days_between
from 
  sample_table
where 
  get_work_days_between(date_field1, date_field2) > 10
;

SQLFiddle examples

于 2013-11-14T04:05:27.660 回答
0
WITH dates AS
(
        SELECT          (TO_DATE('01-JAN-13', 'DD-MON-YY') - 1) + LEVEL       AS d_date
        ,       TO_CHAR((TO_DATE('01-JAN-13', 'DD-MON-YY') - 1) + LEVEL, 'D') AS d_day_no
        FROM    DUAL
        CONNECT BY
                LEVEL < ABS(TO_DATE('01-JAN-13', 'DD-MON-YY') - TO_DATE('31-MAR-13', 'DD-MON-YY')) + 2
)
SELECT  *
FROM    A_TABLE
WHERE   DATE_FIELD IN    -- Instead of: WHERE DATE_FIELD BETWEEN '1-JAN-13' AND '31-MAR-13'
        (
            SELECT  d_date
            FROM    dates
            WHERE   d_day_no NOT IN (6, 7)    -- Skip: Sat and Sun
        )
AND     (DATE_FIELD1 - DATE_FIELD2) > 10
;
于 2013-11-14T09:26:40.017 回答