Oracle SQL:在指定日期之前7天查找日期,不包括星期日和其他特定日期

时间:2018-02-21 10:19:08

标签: sql oracle date oracle10g

我需要在任何指定日期之前7天找到日期。开始日期可以是任何日期,但是,结束日期不应该是星期日或标记为假日的日期。只能连续2个假期。

我的代码可行,但是,它非常冗长。是否有更简单的解决方案?

此外,如果所需的日期范围在将来的某个时间点发生变化,或者连续假期的可能数量发生变化,则需要在多个地方更新脚本,如果可以减少,那么这将是很好的。

我已经有一张桌子(日历),其中包含大量日期,一周中的某一天以及日期是否被视为假日。像这样:

START_DATE, DAY_OF_WEEK, HOLIDAY
10-DEC-17 , Sun        , 0
11-DEC-17 , Mon        , 0
12-DEC-17 , Tue        , 0
13-DEC-17 , Wed        , 0
14-DEC-17 , Thu        , 0
15-DEC-17 , Fri        , 0
16-DEC-17 , Sat        , 0
17-DEC-17 , Sun        , 0
18-DEC-17 , Mon        , 0
19-DEC-17 , Tue        , 0
20-DEC-17 , Wed        , 0
21-DEC-17 , Thu        , 0
22-DEC-17 , Fri        , 0
23-DEC-17 , Sat        , 0
24-DEC-17 , Sun        , 0
25-DEC-17 , Mon        , 1
26-DEC-17 , Tue        , 1
27-DEC-17 , Wed        , 0
28-DEC-17 , Thu        , 0
29-DEC-17 , Fri        , 0
30-DEC-17 , Sat        , 0
31-DEC-17 , Sun        , 0
01-JAN-18 , Mon        , 1
etc...

预期的OUTPUT类似于:

START_DATE, END_DATE
10-DEC-17,  18-DEC-17
11-DEC-17,  18-DEC-17
12-DEC-17,  19-DEC-17
13-DEC-17,  20-DEC-17
14-DEC-17,  21-DEC-17
15-DEC-17,  22-DEC-17
16-DEC-17,  23-DEC-17
17-DEC-17,  27-DEC-17
18-DEC-17,  27-DEC-17
19-DEC-17,  27-DEC-17
20-DEC-17,  27-DEC-17
21-DEC-17,  28-DEC-17
22-DEC-17,  29-DEC-17
23-DEC-17,  30-DEC-17
24-DEC-17,  02-JAN-18
25-DEC-17,  02-JAN-18
26-DEC-17,  02-JAN-18
27-DEC-17,  03-JAN-18
28-DEC-17,  04-JAN-18
etc...

以下是我现有的代码。我的方法是,因为只能连续3天被排除的日子(星期日,然后是2个假日),所以我提前4天检查每个日期,然后选择第一个不是排除日期的日期。其中一个应始终是有效的结束日期。

with temp as
(
select
    start_date,
    case    
        when lead(day_of_week, 7) over(order by start_date) = 'Sun'
          or lead(holiday, 7) over(order by start_date) = 1
        then null
    else
        lead(start_date, 7) over(order by start_date)
    end as days_7,
    case    
        when lead(day_of_week, 8) over(order by start_date) = 'Sun'
          or lead(holiday, 8) over(order by start_date) = 1
        then null
    else
        lead(start_date, 8) over(order by start_date)
    end as days_8,
    case    
        when lead(day_of_week, 9) over(order by start_date) = 'Sun'
          or lead(holiday, 9) over(order by start_date) = 1
        then null
    else
        lead(start_date, 9) over(order by start_date)
    end as days_9,
        case    
        when lead(day_of_week, 10) over(order by start_date) = 'Sun'
          or lead(holiday, 10) over(order by start_date) = 1
        then null
    else
        lead(start_date, 10) over(order by start_date)
    end as days_10
from
    calendar
)

select
    start_date,
    COALESCE(days_7, days_8, days_9, days_10) as end_date 
from
    temp

2 个答案:

答案 0 :(得分:2)

SQL Fiddle

Oracle 11g R2架构设置

CREATE TABLE Calendar( START_DATE, HOLIDAY ) AS
SELECT TO_DATE( '10-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '11-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '12-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '13-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '14-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '15-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '16-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '17-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '18-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '19-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '20-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '21-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '22-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '23-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '24-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '25-DEC-17', 'DD-MON-YY' ), 1 FROM DUAL UNION ALL
SELECT TO_DATE( '26-DEC-17', 'DD-MON-YY' ), 1 FROM DUAL UNION ALL
SELECT TO_DATE( '27-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '28-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '29-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '30-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '31-DEC-17', 'DD-MON-YY' ), 0 FROM DUAL UNION ALL
SELECT TO_DATE( '01-JAN-18', 'DD-MON-YY' ), 1 FROM DUAL;

查询1

SELECT start_date,
       LEAD( end_date, 7 ) OVER ( ORDER BY start_date ) AS end_date
FROM   (
  SELECT start_date,
         LAST_VALUE(
           CASE
           WHEN Holiday = 0
           AND  start_date - TRUNC( start_date, 'IW' ) < 6
           THEN start_date
           END
         ) IGNORE NULLS OVER ( ORDER BY start_date DESC ) AS End_date
  FROM   Calendar
)

<强> Results

|           START_DATE |             END_DATE |
|----------------------|----------------------|
| 2017-12-10T00:00:00Z | 2017-12-18T00:00:00Z |
| 2017-12-11T00:00:00Z | 2017-12-18T00:00:00Z |
| 2017-12-12T00:00:00Z | 2017-12-19T00:00:00Z |
| 2017-12-13T00:00:00Z | 2017-12-20T00:00:00Z |
| 2017-12-14T00:00:00Z | 2017-12-21T00:00:00Z |
| 2017-12-15T00:00:00Z | 2017-12-22T00:00:00Z |
| 2017-12-16T00:00:00Z | 2017-12-23T00:00:00Z |
| 2017-12-17T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-18T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-19T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-20T00:00:00Z | 2017-12-27T00:00:00Z |
| 2017-12-21T00:00:00Z | 2017-12-28T00:00:00Z |
| 2017-12-22T00:00:00Z | 2017-12-29T00:00:00Z |
| 2017-12-23T00:00:00Z | 2017-12-30T00:00:00Z |
| 2017-12-24T00:00:00Z |               (null) |
| 2017-12-25T00:00:00Z |               (null) |
| 2017-12-26T00:00:00Z |               (null) |
| 2017-12-27T00:00:00Z |               (null) |
| 2017-12-28T00:00:00Z |               (null) |
| 2017-12-29T00:00:00Z |               (null) |
| 2017-12-30T00:00:00Z |               (null) |
| 2017-12-31T00:00:00Z |               (null) |
| 2018-01-01T00:00:00Z |               (null) |

答案 1 :(得分:0)

给出假期表:

with holidays as ( 
select to_date('10-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('11-DEC-17','dd-MON-YY') as mydate , 'Mon' as myday, 0 holiday from dual
union all
select to_date('12-DEC-17','dd-MON-YY') as mydate , 'Tue' as myday, 0 holiday from dual
union all
select to_date('13-DEC-17','dd-MON-YY') as mydate , 'Wed' as myday, 0 holiday from dual
union all
select to_date('14-DEC-17','dd-MON-YY') as mydate , 'Thu' as myday, 0 holiday from dual
union all
select to_date('15-DEC-17','dd-MON-YY') as mydate , 'Fri' as myday, 0 holiday from dual
union all
select to_date('16-DEC-17','dd-MON-YY') as mydate , 'Sat' as myday, 0 holiday from dual
union all
select to_date('17-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('18-DEC-17','dd-MON-YY') as mydate , 'Mon' as myday, 0 holiday from dual
union all
select to_date('19-DEC-17','dd-MON-YY') as mydate , 'Tue' as myday, 0 holiday from dual
union all
select to_date('20-DEC-17','dd-MON-YY') as mydate , 'Wed' as myday, 0 holiday from dual
union all
select to_date('21-DEC-17','dd-MON-YY') as mydate , 'Thu' as myday, 0 holiday from dual
union all
select to_date('22-DEC-17','dd-MON-YY') as mydate , 'Fri' as myday, 0 holiday from dual
union all
select to_date('23-DEC-17','dd-MON-YY') as mydate , 'Sat' as myday, 0 holiday from dual
union all
select to_date('24-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('25-DEC-17','dd-MON-YY') as mydate , 'Mon' as myday, 1 holiday from dual
union all
select to_date('26-DEC-17','dd-MON-YY') as mydate , 'Tue' as myday, 1 holiday from dual
union all
select to_date('27-DEC-17','dd-MON-YY') as mydate , 'Wed' as myday, 0 holiday from dual
union all
select to_date('28-DEC-17','dd-MON-YY') as mydate , 'Thu' as myday, 0 holiday from dual
union all
select to_date('29-DEC-17','dd-MON-YY') as mydate , 'Fri' as myday, 0 holiday from dual
union all
select to_date('30-DEC-17','dd-MON-YY') as mydate , 'Sat' as myday, 0 holiday from dual
union all
select to_date('31-DEC-17','dd-MON-YY') as mydate , 'Sun' as myday, 0 holiday from dual
union all
select to_date('01-JAN-18','dd-MON-YY') as mydate , 'Mon' as myday, 1 holiday from dual),

在这里,我找到工作日,然后使用第一行来获得所需的日期

working as (
select holidays.*, case when myday='Sun' or holiday=1 
 then 0 else 1 end as working_day  from holidays
)
select  mydate from (
select mydate from working where 
   mydate>=to_date('21/12/2017','dd/mm/rrrr')+7
   order by (case when working_day=0 then null  else mydate end) asc nulls last
) where rownum=1