SQL返回日期中传递的2个工作日数

时间:2012-10-17 11:07:42

标签: sql oracle date plsql datediff

我需要编写一个sql查询,返回两个给定日期之间的工作日数(周一至周五)。

我想知道最有效的方法是什么?

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

然后能够从圣诞节和拳击日等计算中删除假期也很有帮助。

任何想法?

6 个答案:

答案 0 :(得分:3)

这很简单:

    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.

答案 1 :(得分:3)

计算2个日期之间工作日数的简便方法是:

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

答案 2 :(得分:1)

这是一个例子

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')

示范

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                                                                      

答案 3 :(得分:1)

可以通过以下方式实现:

select  SUM(decode ( to_CHAR((sysdate-ROWNUM),'DY'),'SUN',0,'SAT',0,1)) from all_objects where rownum < sysdate -  (sysdate -9) 

答案 4 :(得分:0)

你去......

  1. 首先检查假期表中有多少天,不包括周末。
  2. 在两个日期之间获取工作日(MON到FRI),然后减去假期。

    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;
    
  3. 之后你可以测试一下,如:

        select 
                calculate_business_days('21-AUG-2013','28-AUG-2013') as business_days 
        from dual;
    

答案 5 :(得分:0)

这就是我这样做的方式,假设你已经有了一个带有列表的日历表,表明一天是否工作日: 在您的日历表中添加一个新列,例如workday_num,并使用

使用正在运行的数字填充一次
sum(case when workingday then 1 else 0 end)
over (order by calendardate rows unbounded preceding)

现在它是你的日历的两个连接,以及p_start_date和p_end_date的workday_nums的简单区别。