2011-03-09 69 views
5

我可以說一個「旅行日期」和黑棗日期。 根據日期不同,我會將旅行日期分成小段。PL/SQL Split,根據日期不同將日期分爲新日期!

注:行程日期可0 - 9999 99 99之間

樣品:

Travel Date: 
Travel | START DATE | END DATE 
T  | 2011 01 04 | 2011 12 11 

Black Out Dates: 
BO | START DATE | END DATE 
A | 2010 11 01 | 2011 02 11 
B | 2011 01 20 | 2011 02 15 
C | 2011 03 13 | 2011 04 10 
D | 2011 03 20 | 2011 06 29 

的例外結果:

New Travel | START DATE | END DATE 
X1   | 2011 02 16 | 2011 03 12 
X2   | 2011 06 30 | 2011 12 11 

視覺:

NAME  : date range 
Travel Date : -----[--------------------------]-- 

A   : --[------]------------------------- 
B   : ------[---]------------------------ 
C   : --------------[---]---------------- 
D   : ----------------[------]----------- 

結果:

X1   : -----------[--]-------------------- 
X2   : -----------------------[--------]-- 

示例2:

Travel Date : -[--------------------------------]-- 

BO Date A : ----[------]------------------------- 
BO Date B : ----------------------[------]------- 
BO Date C : --------------------[---]------------ 
BO Date D : ------------------[------]----------- 

Result X1 : -[--]-------------------------------- 
Result X2 : -----------[------]------------------ 
Result X3 : -----------------------------[----]-- 

示例3:

Travel Date : ]-----------------------------------[ 

BO Date A : ----[------]------------------------- 
BO Date B : -------------------------[---]------- 
BO Date C : ----------------[---]---------------- 
BO Date D : ------------------[------]----------- 

Result X1 : ---]--------------------------------- 
Result X2 : -----------[--]---------------------- 
Result X3 : -----------------------------[------- 

我怎樣才能做到這一點使用PL SQL?

謝謝。

下面是表和測試用例:

DROP TABLE TRACES.TRAVEL CASCADE CONSTRAINTS; 

CREATE TABLE TRACES.TRAVEL 
(
    START_DATE DATE, 
    END_DATE DATE 
); 

DROP TABLE TRACES.BLACK_OUT_DATES CASCADE CONSTRAINTS; 

CREATE TABLE TRACES.BLACK_OUT_DATES 
(
    BO   CHAR(1 BYTE), 
    START_DATE DATE, 
    END_DATE  DATE 
); 

/* 
TEST CASE 1 
------------------------------------------------------------------- 
Expected Results: 
01/01/0001 09/02/2011 
16/02/2011 01/04/2011 
21/04/2011 10/05/2011 
16/06/2011 19/11/2011 
30/11/2011 31/12/9999 

Visually: 
Travel: 
---------------------------------------------------- 

BO: 
--[--]---------------------------------------------- 
---------------[------]----------------------------- 
-----------------------------[---------------]------ 

Result: 
[-]---[--------]-------[-----]----------------[-----] 

*/ 

TRUNCATE TABLE TRACES.TRAVEL; 

TRUNCATE TABLE TRACES.BLACK_OUT_DATES; 

INSERT INTO TRACES.TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '0001-01-01', DATE '9999-12-31'); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-02-10', DATE '2011-02-15'); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-04-02', DATE '2011-04-20' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-05-11', DATE '2011-06-15' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-11-20', DATE '2011-11-29' ); 
--INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('E', DATE '2011-05-09', DATE '2011-05-12' ); 

COMMIT; 

SELECT * FROM BLACK_OUT_DATES; 
SELECT * FROM TRAVEL; 

/* 
TEST CASE 2 
------------------------------------------------------------------- 
Expected Results: 
01/01/2011 01/02/2011 
07/05/2011 06/07/2011 
21/07/2011 31/12/2011 

Visually: 
Travel: 
[------------------------------------------------------] 

BO: 
--[----------------------]------------------------------ 
---------------[--]------------------------------------- 
---------------------------------[--------]------------- 
----------------------------------------[--------]------ 

Result: 
[--]---------------------[---------]--------------[----] 

*/ 
TRUNCATE TABLE TRACES.TRAVEL; 

TRUNCATE TABLE TRACES.BLACK_OUT_DATES; 

INSERT INTO TRACES.TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-01-01', DATE '2011-12-31'); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-02-02', DATE '2011-05-06'); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-03-03', DATE '2011-03-05' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-07-07', DATE '2011-07-09' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-07-08', DATE '2011-07-20' ); 

COMMIT; 

SELECT * FROM BLACK_OUT_DATES; 
SELECT * FROM TRAVEL; 

/* 
TEST CASE 3 
------------------------------------------------------------------- 
Expected Results: 
04/05/2011 03/06/2011 
21/06/2011 07/08/2011 

Visually: 
Travel: 
[------------------------------------------------------] 

BO: 
--[----------------------]------------------------------ 
---------------[--]------------------------------------- 
---------------------------------[--------]------------- 
----------------------------------------[--------]------ 

Result: 
[--]---------------------[---------]--------------[----] 
*/ 

TRUNCATE TABLE TRACES.TRAVEL; 

TRUNCATE TABLE TRACES.BLACK_OUT_DATES; 

INSERT INTO TRACES.TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-04-02', DATE '2011-10-20' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-01-01', DATE '2011-05-03' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-06-04', DATE '2011-06-20' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-06-06', DATE '2011-06-08' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-08-08', DATE '2011-12-30' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('E', DATE '2011-08-08', DATE '2011-12-30' ); 

COMMIT; 

SELECT * FROM BLACK_OUT_DATES; 
SELECT * FROM TRAVEL; 

/* 
TEST CASE 4 
------------------------------------------------------------------- 
Expected Results: 
21/02/2011 09/04/2011 
26/04/2011 09/05/2011 

Visually: 
Travel: 
----[-------------------------]------------------------- 

BO: 
--[----]------------------------------------------------ 
----[----]---------------------------------------------- 
-------------[--------]--------------------------------- 
------------------[--]---------------------------------- 
--------------------------[--------]-------------------- 

Result: 
----------[--]--------[--]----------------------------- 
*/ 

TRUNCATE TABLE TRACES.TRAVEL; 

TRUNCATE TABLE TRACES.BLACK_OUT_DATES; 

INSERT INTO TRACES.TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-02-10', DATE '2011-05-15' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-02-02', DATE '2011-02-15' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-02-10', DATE '2011-02-20' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-04-10', DATE '2011-04-25' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-04-15', DATE '2011-04-20' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('E', DATE '2011-05-10', DATE '2011-05-20' ); 

COMMIT; 

SELECT * FROM BLACK_OUT_DATES; 
SELECT * FROM TRAVEL; 

/* 
TEST CASE 5 
------------------------------------------------------------------- 
Expected Results: 
21/02/2011 04/05/2011 

Visually: 
Travel: 
------[-------------------------]----------------------- 

BO: 
-[-----]------------------------------------------------ 
--[--]-------------------------------------------------- 
----------------------------[--------]------------------ 
------------------------------[-----]------------------- 
-------------------------------[--]--------------------- 

Result: 
--------[-------------------]--------------------------- 
*/ 

TRUNCATE TABLE TRACES.TRAVEL; 

TRUNCATE TABLE TRACES.BLACK_OUT_DATES; 

INSERT INTO TRACES.TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-02-10', DATE '2011-05-17' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-02-05', DATE '2011-02-20' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-02-07', DATE '2011-02-09' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-05-05', DATE '2011-05-20' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-05-07', DATE '2011-05-15' ); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('E', DATE '2011-05-09', DATE '2011-05-12' ); 

COMMIT; 

SELECT * FROM BLACK_OUT_DATES; 
SELECT * FROM TRAVEL; 

/* 
TEST CASE 6 
------------------------------------------------------------------- 
Expected Results: 
No Result 

Visually: 
Travel: 
------[----------------------------]-------------------- 

BO: 
--[---------------------------------------]------------- 

Result: 
No Result 

*/ 

TRUNCATE TABLE TRACES.TRAVEL; 

TRUNCATE TABLE TRACES.BLACK_OUT_DATES; 

INSERT INTO TRACES.TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-02-10', DATE '2011-09-20'); 
INSERT INTO TRACES.BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-01-05', DATE '2011-10-10'); 

COMMIT; 

SELECT * FROM BLACK_OUT_DATES; 
SELECT * FROM TRAVEL; 
+1

順便說一下,'9999 99 99'不是有效的日期... – 2011-03-10 06:56:04

+0

您確實將日期存儲爲NUMBER(8)嗎? – 2011-03-10 10:05:25

+0

它代表無限,而不是特定的日期。例如: 例如:開始日期:00010101結束日期:99991231。表現應該很快。 – ahmet 2011-03-10 10:09:05

回答

5

你的表:

SQL> create table travel (start_date,end_date) 
    2 as 
    3 select date '2011-01-04', date '2011-12-11' from dual 
    4/

Table created. 

SQL> create table black_out_dates (bo,start_date,end_date) 
    2 as 
    3 select 'A', date '2010-11-01', date '2011-02-11' from dual union all 
    4 select 'B', date '2011-01-20', date '2011-02-15' from dual union all 
    5 select 'C', date '2011-03-13', date '2011-04-10' from dual union all 
    6 select 'D', date '2011-03-20', date '2011-06-29' from dual 
    7/

Table created. 

和查詢,其中考慮到完全重疊的黑色超時週期:在大多數N + 1

SQL> select 'X' || to_char(row_number() over (order by new_start_date)) new_travel 
    2  , new_start_date 
    3  , new_end_date 
    4 from (select end_date + 1 new_start_date 
    5    , lead(start_date - 1, 1, t_end_date) over (order by start_date) new_end_date 
    6    from (select start_date 
    7       , end_date 
    8       , t_end_date 
    9       , row_number() over (order by start_date) rn_start_date 
10       , row_number() over (order by end_date) rn_end_date 
11      from (select bo.start_date 
12         , bo.end_date 
13         , t.end_date t_end_date 
14        from black_out_dates bo 
15         , travel t 
16        where t.start_date <= bo.end_date 
17        and t.end_date >= bo.start_date 
18        union all 
19        select start_date - 1 
20         , start_date - 1 
21         , null 
22        from travel 
23       ) 
24     ) 
25   where rn_start_date <= rn_end_date 
26  ) 
27 where new_start_date <= new_end_date 
28 order by new_start_date 
29/

NEW_TRAVEL NEW_START_DATE  NEW_END_DATE 
---------- ------------------- ------------------- 
X1   16-02-2011 00:00:00 12-03-2011 00:00:00 
X2   30-06-2011 00:00:00 11-12-2011 00:00:00 

2 rows selected. 

如果您black_out_dates表包含N行,則有差距。該查詢在[2011-01-03,2011-01-03]中構成一個虛擬黑屏日期,然後使用分析函數LEAD確定下一個黑屏日期的起始位置。 ROW_NUMBER分析函數刪除完全重疊的時間段,因爲它們會縮短間隔時間。


編輯14-3-2011

這些表:

SQL> create table travel (start_date,end_date) 
    2 as 
    3 select date '2001-01-04', date '2013-12-11' from dual 
    4/

Table created. 

SQL> create table black_out_dates (bo,start_date,end_date) 
    2 as 
    3 select 'A', date '2010-11-01', date '2011-02-11' from dual union all 
    4 select 'B', date '2011-01-20', date '2011-02-15' from dual union all 
    5 select 'C', date '2011-03-13', date '2011-04-10' from dual union all 
    6 select 'D', date '2011-03-20', date '2011-06-29' from dual 
    7/

Table created. 

我以前的查詢還是沒有正確處理重疊的時段。因此,這裏是一個修訂版,方便地存儲在視圖V:

SQL> create view v 
    2 as 
    3 with t1 as 
    4 (select bo.start_date 
    5   , bo.end_date 
    6   , t.end_date t_end_date 
    7  from black_out_dates bo 
    8   , travel t 
    9  where bo.start_date <= t.end_date 
10  and bo.end_date >= t.start_date 
11  union all 
12 select start_date - 1 
13   , start_date - 1 
14   , end_date 
15  from travel 
16 ) 
17 , t2 as 
18 (select t1.* 
19   , nvl 
20   (max(end_date) 
21    over 
22    (order by start_date,end_date desc 
23    rows between unbounded preceding and 1 preceding 
24   ) 
25   , to_date('1','j') 
26   ) max_date 
27  from t1 
28 ) 
29 , t3 as 
30 (select start_date 
31   , end_date 
32   , t_end_date 
33   , sum(case when start_date > max_date then 1 else 0 end) 
34   over 
35   (order by start_date, end_date desc) grp 
36  from t2 
37 ) 
38 , t4 as 
39 (select max(end_date) + 1 new_start_date 
40   , lead(min(start_date) - 1, 1, t_end_date) over (order by min(start_date)) new_end_date 
41  from t3 
42  group by t_end_date 
43   , grp 
44 ) 
45 select new_start_date 
46  , new_end_date 
47 from t4 
48 where new_start_date <= new_end_date 
49/

View created. 

,測試結果:

SQL> set feedback off 
SQL> remark Test 1 
SQL> select * from v 
    2/

NEW_START_DATE  NEW_END_DATE 
------------------- ------------------- 
04-01-2001 00:00:00 31-10-2010 00:00:00 
16-02-2011 00:00:00 12-03-2011 00:00:00 
30-06-2011 00:00:00 11-12-2013 00:00:00 
SQL> remark Test 2 
SQL> delete travel 
    2/
SQL> delete black_out_dates 
    2/
SQL> INSERT INTO TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-01-01', DATE '2011-12-31'); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-02-02', DATE '2011-05-06'); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-03-03', DATE '2011-03-05' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-07-07', DATE '2011-07-09' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-07-08', DATE '2011-07-20' ); 
SQL> select * from v 
    2/

NEW_START_DATE  NEW_END_DATE 
------------------- ------------------- 
01-01-2011 00:00:00 01-02-2011 00:00:00 
07-05-2011 00:00:00 06-07-2011 00:00:00 
21-07-2011 00:00:00 31-12-2011 00:00:00 
SQL> remark Test 3 
SQL> delete travel 
    2/
SQL> delete black_out_dates 
    2/
SQL> INSERT INTO TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-04-02', DATE '2011-10-20' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-01-01', DATE '2011-05-03' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-06-04', DATE '2011-06-20' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-06-06', DATE '2011-06-08' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-08-08', DATE '2011-12-30' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('E', DATE '2011-08-08', DATE '2011-12-30' ); 
SQL> select * from v 
    2/

NEW_START_DATE  NEW_END_DATE 
------------------- ------------------- 
04-05-2011 00:00:00 03-06-2011 00:00:00 
21-06-2011 00:00:00 07-08-2011 00:00:00 
SQL> remark Test 4 
SQL> delete travel 
    2/
SQL> delete black_out_dates 
    2/
SQL> INSERT INTO TRAVEL( START_DATE, END_DATE)     VALUES ( DATE '2011-02-10', DATE '2011-05-15' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-02-02', DATE '2011-02-15' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-02-10', DATE '2011-02-20' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-04-10', DATE '2011-04-25' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-04-15', DATE '2011-04-20' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('E', DATE '2011-05-10', DATE '2011-05-20' ); 
SQL> select * from v 
    2/

NEW_START_DATE  NEW_END_DATE 
------------------- ------------------- 
21-02-2011 00:00:00 09-04-2011 00:00:00 
26-04-2011 00:00:00 09-05-2011 00:00:00 
SQL> remark Test 5 
SQL> delete travel 
    2/
SQL> delete black_out_dates 
    2/
SQL> INSERT INTO TRAVEL VALUES ( DATE '2011-02-10', DATE '2011-05-17' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('A', DATE '2011-02-05', DATE '2011-02-20' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('B', DATE '2011-02-07', DATE '2011-02-09' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('C', DATE '2011-05-05', DATE '2011-05-20' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('D', DATE '2011-05-07', DATE '2011-05-15' ); 
SQL> INSERT INTO BLACK_OUT_DATES(BO, START_DATE, END_DATE) VALUES ('E', DATE '2011-05-09', DATE '2011-05-12' ); 
SQL> select * from v 
    2/

NEW_START_DATE  NEW_END_DATE 
------------------- ------------------- 
21-02-2011 00:00:00 04-05-2011 00:00:00 
SQL> remark Test 6 
SQL> delete travel 
    2/
SQL> delete black_out_dates 
    2/
SQL> INSERT INTO TRAVEL VALUES (DATE '2011-02-10', DATE '2011-09-20'); 
SQL> INSERT INTO BLACK_OUT_DATES VALUES ('A', DATE '2011-01-05', DATE '2011-10-10'); 
SQL> select * from v 
    2/

問候,
羅布。

+0

謝謝。 @ Rob-van-Wijk 你的回答非常有幫助。 – ahmet 2011-03-10 15:33:13

+0

但將旅行日期更改爲04/01/2001 - 11/12/2013應顯示結果爲

 '**04/01/2001 \t 31/10/2010** 16/02/2011 \t 12/03/2011 30/06/2011 \t **11/12/2013**'
不會生成:'02/01/2001-31/10/2010' – ahmet 2011-03-10 16:25:40

+0

@ahmet:我剛剛檢查它和我的查詢完全返回三行與新的輸入... – 2011-03-11 09:07:41

7

這將返回存在的旅行日期的所有日期的離散名單範圍,但不是在限制日期列表,然後將它們組合使用Oracle - Convert value from rows into ranges

WITH traveldate AS 
    (SELECT TO_DATE('2011 01 04','YYYY MM DD') AS start_date 
     ,TO_DATE('2011 12 11','YYYY MM DD') AS end_date FROM DUAL) 
    ,blackout AS 
    (SELECT TO_DATE('2010 11 01','YYYY MM DD') AS start_date 
     ,TO_DATE('2011 02 11','YYYY MM DD') AS end_date FROM DUAL 
    UNION ALL 
    SELECT TO_DATE('2011 01 20','YYYY MM DD') AS start_date 
     ,TO_DATE('2011 02 15','YYYY MM DD') AS end_date FROM DUAL 
    UNION ALL 
    SELECT TO_DATE('2011 03 13','YYYY MM DD') AS start_date 
     ,TO_DATE('2011 04 10','YYYY MM DD') AS end_date FROM DUAL 
    UNION ALL 
    SELECT TO_DATE('2011 03 20','YYYY MM DD') AS start_date 
     ,TO_DATE('2011 06 29','YYYY MM DD') AS end_date FROM DUAL) 
    ,days AS 
    (SELECT TO_DATE('2010 01 01','YYYY MM DD') + ROWNUM d 
    FROM DUAL CONNECT BY LEVEL <= 1000) 
    ,base AS 
    (SELECT d AS n 
    FROM days, traveldate 
    WHERE d >= traveldate.start_date AND d <= traveldate.end_date 
    MINUS 
    SELECT d AS n 
    FROM days, blackout 
    WHERE d >= blackout.start_date AND d <= blackout.end_date 
) 
,lagged AS 
(
    SELECT n, LAG(n) OVER (ORDER BY n) lag_n FROM base 
) 
, groups AS 
(
    SELECT n, row_number() OVER (ORDER BY n) groupnum 
     FROM lagged 
     WHERE lag_n IS NULL OR lag_n < n-1 
) 
, grouped AS 
(
    SELECT n, (SELECT MAX(groupnum) FROM groups 
       WHERE groups.n <= base.n 
      ) groupnum 
     FROM base 
) 
SELECT groupnum, MIN(n), MAX(n) 
    FROM grouped 
    GROUP BY groupnum 
    ORDER BY groupnum; 

結果:

GROUPNUM MIN(N)   MAX(N) 

1   16/02/2011 12/03/2011 
2   30/06/2011 11/12/2011 
+0

謝謝。 @傑弗裏 - 坎普。 但如果我們的日期介於開始日期:'00010101'結束日期:'99991231'之間會發生什麼情況。我們必須將'CONNECT BY LEVEL <= 1000'更改爲更大的數字,並且**性能**將下降。 – ahmet 2011-03-10 15:30:08

+1

@ahment性能將下降,計算10000年的任何事情,但首先我不認爲這是你的情況,其次,你可以通過生成天子查詢僅在第二天結束後輕鬆優化它。首先封鎖並且前一天到最後封鎖的開始。然後,爲0001 01 01生成兩個新組,分別爲第一個封鎖 - 1和最後一個封鎖+ 1至9999 12 31(如果需要)。你甚至可以在與工會同一句話中做到這一點。 – jachguate 2011-03-11 00:00:23

+0

@ahmet,試試看,你可能會發現它表現相當好,無論如何。 jachguate的建議也很好地減少了生成的行數。您可以從traveldate和blackout表中獲取MIN和MAX日期,並生成所需的最小行數。 – 2011-03-11 01:55:31