Question: 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 to do this?

```
SELECT           --Start with total number of days including weekends             
(DATEDIFF(dd,@StartDate,@EndDate)+1) --Subtact 2 days for each full weekend 
(DATEDIFF(wk,@StartDate,@EndDate)*2) --If StartDate is a Sunday, Subtract 1          
ELSE 0               END)            --If EndDate is a Saturday, Subtract 1 
FROM dual

```

Then it would also be helpful to be able to remove holidays from this count such as christmas day and boxing day.

Any Ideas?

Answer: 
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

```
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;

```