SQL to return the number of working days between 2 passed in dates

前端 未结 6 1559
礼貌的吻别
礼貌的吻别 2021-01-07 08:10

I need to write an sql query that returns the number of Working days (Monday - Friday) between two given dates.

I was wondering what would be the most efficient way

相关标签:
6条回答
  • 2021-01-07 08:36

    This is how i do it, assuming you already got a calendar table with acolumn which indicates if a day is working day or not: Add a new column to your calendar table like workday_num and populate it once with a running number using

    sum(case when workingday then 1 else 0 end)
    over (order by calendardate rows unbounded preceding)
    

    Now it's two joins to your calendar and a simple difference of the workday_nums of p_start_date and p_end_date.

    0 讨论(0)
  • 2021-01-07 08:41

    Thats so simple :

        SQL> Select count(*)
          2  from ( select rownum rnum
          3          from all_objects
          4        where rownum <= to_date('18-dec-2009','dd-mon-yyyy') - 
        to_date('16-nov-2009')+1 )
          5    where to_char( to_date('16-nov-2009','dd-mon-yyyy')+rnum-1, 'DY' )
          6                not in ( 'SAT', 'SUN' )
    
    
          COUNT(*)
        ----------
                25
    
        SQL> Select to_char( to_date('16-nov-2009','dd-mon-yyyy')+rnum-1, 'DY dd-mon-yyyy' )
          2  from ( select rownum rnum
          3          from all_objects
          4        where rownum <= to_date('18-dec-2009','dd-mon-yyyy') - to_date('16-nov-2009')+1 )
          5    where to_char( to_date('16-nov-2009','dd-mon-yyyy')+rnum-1, 'DY' )
          6                not in ( 'SAT', 'SUN' )
    
    
    DAY_DATE
    ---------------
    MON 16-nov-2009
    TUE 17-nov-2009
    WED 18-nov-2009
    THU 19-nov-2009
    FRI 20-nov-2009
    MON 23-nov-2009
    TUE 24-nov-2009
    WED 25-nov-2009
    THU 26-nov-2009
    FRI 27-nov-2009
    MON 30-nov-2009
    TUE 01-dec-2009
    WED 02-dec-2009
    THU 03-dec-2009
    FRI 04-dec-2009
    MON 07-dec-2009
    TUE 08-dec-2009
    WED 09-dec-2009
    THU 10-dec-2009
    FRI 11-dec-2009
    MON 14-dec-2009
    TUE 15-dec-2009
    WED 16-dec-2009
    THU 17-dec-2009
    FRI 18-dec-2009
    
    25 rows selected.
    
    0 讨论(0)
  • 2021-01-07 08:44

    It can be achieved by:

    select  SUM(decode ( to_CHAR((sysdate-ROWNUM),'DY'),'SUN',0,'SAT',0,1)) from all_objects where rownum < sysdate -  (sysdate -9) 
    
    0 讨论(0)
  • 2021-01-07 08:52

    an easy way to calculate to number of weekdays between 2 dates is :

    SELECT
    date1,
    date2,
    ((date2-date1)-2*FLOOR((date2-date1)/7)-DECODE(SIGN(TO_CHAR(date2,'D')-
        TO_CHAR(date1,'D')),-1,2,0)+DECODE(TO_CHAR(date1,'D'),7,1,0)-
        DECODE(TO_CHAR(date2,'D'),7,1,0))*24 as WorkDays
    FROM
      tablename
    ORDER BY date1,date2
    
    0 讨论(0)
  • 2021-01-07 08:52

    Here is an example

    with given_days(d) as(
      select <<start_date>> + level - 1
        from dual
      connect by level < = (<<end_date>> - <<start_date>>) + 1
    )
    select count(*)
      from given_days
    where to_char(d, 'DY', 'NLS_DATE_LANGUAGE=english') not in ('SUN', 'SAT')
    

    Demonstration

    HR\XE> with given_days as(
      2    select (to_date('&&1', 'dd.mm.yyyy') + level - 1) as g_day
      3      from dual
      4    connect by level < = (to_date('&2', 'dd.mm.yyyy') - to_date('&&1', 'dd.mm.yyyy')) + 1
      5  )
      6  select count(g_day) as cnt
      7    from given_days
      8  where to_char(g_day, 'DY', 'NLS_DATE_LANGUAGE=english') not in ('SUN', 'SAT');
    Enter value for 1: 10.10.2012
    old   2:   select to_date('&&1', 'dd.mm.yyyy') + level - 1
    new   2:   select to_date('10.10.2012', 'dd.mm.yyyy') + level - 1
    Enter value for 2: 17.10.2012
    old   4:   connect by level < = (to_date('&2', 'dd.mm.yyyy') - to_date('&&1', 'dd.mm.yyyy')) + 1
    new   4:   connect by level < = (to_date('17.10.2012', 'dd.mm.yyyy') - to_date('10.10.2012', 'dd.mm.yyyy')) + 1
    
      cnt                                                                     
    ----------                           
       6                                                                      
    
    0 讨论(0)
  • 2021-01-07 08:54

    Here you go...

    1. First check how many days you got in the holiday table, excluding weekend days.
    2. Get business days (MON to FRI) between the 2 dates and after that subtract the holiday days.

      create or replace
      FUNCTION calculate_business_days (p_start_date IN DATE, p_end_date IN DATE)
              RETURN NUMBER IS
              v_holidays     NUMBER;
              v_start_date   DATE   := TRUNC (p_start_date);
              v_end_date     DATE   := TRUNC (p_end_date);
              BEGIN
              IF v_end_date >= v_start_date
              THEN
                      SELECT COUNT (*)
                      INTO v_holidays
                      FROM holidays
                      WHERE day BETWEEN v_start_date AND v_end_date
                      AND day NOT IN (
                              SELECT hol.day 
                              FROM holidays hol 
                              WHERE MOD(TO_CHAR(hol.day, 'J'), 7) + 1 IN (6, 7)
                      );
      
              RETURN   GREATEST (NEXT_DAY (v_start_date, 'MON') - v_start_date - 2, 0)
                   +   (  (  NEXT_DAY (v_end_date, 'MON')
                           - NEXT_DAY (v_start_date, 'MON')
                          )
                        / 7
                       )
                     * 5
                   - GREATEST (NEXT_DAY (v_end_date, 'MON') - v_end_date - 3, 0)
                   - v_holidays;
              ELSE
                      RETURN NULL;
              END IF;
      END calculate_business_days;
      

    After that you can test it out, like:

        select 
                calculate_business_days('21-AUG-2013','28-AUG-2013') as business_days 
        from dual;
    
    0 讨论(0)
提交回复
热议问题