我需要编写一个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
然后能够从圣诞节和拳击日等计算中删除假期也很有帮助。
任何想法?
答案 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)
你去......
在两个日期之间获取工作日(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;
之后你可以测试一下,如:
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的简单区别。