Calculating working days including holidays between dates without a calendar table in oracle SQL

后端 未结 2 816
借酒劲吻你
借酒劲吻你 2021-01-15 05:05

Okay, so I\'ve done quite a lot of reading on the possibility of emulating the networkdays function of excel in sql, and have come to the conclusion that by far the easiest

2条回答
  •  无人及你
    2021-01-15 05:54

    There are a few ways to do this. Perhaps the simplest might be to create a CTE that produces a virtual calendar table, based on Oracle's connect by syntax, and then join it to the Assesments table, like so:

    with calendar_cte as (
    select to_date('01-01-2000')+level-1 calendar_date,
           case when to_char(to_date('01-01-2000')+level-1, 'Day') 
                    in ('Sunday   ','Saturday ') then 0
                when to_date('01-01-2000')+level-1
                    in ('03-01-2000','21-04-2000','24-04-2000','01-05-2000','29-05-2000','28-08-2000','25-12-2000','26-12-2000','01-01-2001','13-04-2001','16-04-2001','07-05-2001','28-05-2001','27-08-2001','25-12-2001','26-12-2001','01-01-2002','29-03-2002','01-04-2002','06-04-2002','03-06-2002','04-06-2002','26-08-2002','25-12-2002','26-12-2002','01-01-2003','18-04-2003','21-04-2003','05-05-2003','26-05-2003','25-08-2003','25-12-2003','26-12-2003','01-01-2004','09-04-2004','12-04-2004','03-05-2004','31-05-2004','30-08-2004','25-12-2004','26-12-2004','27-12-2004','28-12-2004','01-01-2005','03-01-2005','25-03-2005','28-03-2005','02-05-2005','30-05-2005','29-08-2005','27-12-2005','28-12-2005','02-01-2006','14-04-2006','17-04-2006','01-05-2006','29-05-2006','28-08-2006','25-12-2006','26-12-2006','02-01-2007','06-04-2007','09-04-2007','07-05-2007','28-05-2007','27-08-2007','25-12-2007','26-12-2007','01-01-2008','21-03-2008','24-03-2008','05-05-2008','26-05-2008','25-08-2008','25-12-2008','26-12-2008','01-01-2009','10-04-2009','13-04-2009','04-05-2009','25-05-2009','31-08-2009','25-12-2009','28-12-2009','01-01-2010','02-04-2010','05-04-2010','03-05-2010','31-05-2010','30-08-2010','24-12-2010','27-12-2010','28-12-2010','31-12-2010','03-01-2011','22-04-2011','25-04-2011','29-04-2011','02-05-2011','30-05-2011','29-08-2011','26-12-2011','27-12-2011') 
                    then 0 
                else 1
           end working_day
    from dual
    connect by level <= 36525 + sysdate - to_date('01-01-2000') )
    SELECT a.ASM_ID,
           a.ASM_START_DATE,
           a.ASM_END_DATE,
           sum(c.working_day) AS Week_Day
    From O_ASSESSMENTS a
    join calendar_cte c 
      on c.calendar_date between a.ASM_START_DATE and a.ASM_END_DATE
    WHERE a.ASM_QSA_ID  IN ('TYPE1') and 
          a.ASM_END_DATE >= '01/01/2012' -- and a.ASM_ID = 'A00000'
    GROUP BY
          a.ASM_ID,
          a.ASM_START_DATE,
          a.ASM_END_DATE
    

    This will produce a virtual table populated with dates from 01 January 2000 to 10 years after the current date, with all weekends marked as non-working days and all days specified in the second in clause (ie. up to 27 December 2011) also marked as non-working days.

    The drawback of this method (or any method where the holiday dates are hardcoded into the query) is that each time new holiday dates are defined, every single query that uses this approach will have to have those dates added.

提交回复
热议问题