これはギャップと島の問題です。それにアプローチするさまざまな方法があります。これはlead
を使用します およびlag
分析関数:
select distinct product,
case when start_date is null then lag(start_date)
over (partition by product order by rn) else start_date end as start_date,
case when end_date is null then lead(end_date)
over (partition by product order by rn) else end_date end as end_date
from (
select product, start_date, end_date, rn
from (
select t.product,
case when lag(end_date)
over (partition by product order by start_date) is null
or lag(end_date)
over (partition by product order by start_date) != start_date - 1
then start_date end as start_date,
case when lead(start_date)
over (partition by product order by start_date) is null
or lead(start_date)
over (partition by product order by start_date) != end_date + 1
then end_date end as end_date,
row_number() over (partition by product order by start_date) as rn
from t
)
where start_date is not null or end_date is not null
)
order by start_date, product;
PRODUCT START_DATE END_DATE
------- ---------- ---------
A 01-JUL-13 30-SEP-13
B 01-OCT-13 30-NOV-13
A 01-DEC-13 31-MAR-14
最も内側のクエリは、製品の前後のレコードを調べ、レコードが連続していない場合にのみ開始時刻や終了時刻を保持します。
select t.product,
case when lag(end_date)
over (partition by product order by start_date) is null
or lag(end_date)
over (partition by product order by start_date) != start_date - 1
then start_date end as start_date,
case when lead(start_date)
over (partition by product order by start_date) is null
or lead(start_date)
over (partition by product order by start_date) != end_date + 1
then end_date end as end_date
from t;
PRODUCT START_DATE END_DATE
------- ---------- ---------
A 01-JUL-13
A
A 30-SEP-13
A 01-DEC-13
A
A
A 31-MAR-14
B 01-OCT-13
B 30-NOV-13
次のレベルのselectは、両方の日付が内部クエリによって空白にされた中間期間のものを削除します。これにより、次のようになります。
PRODUCT START_DATE END_DATE
------- ---------- ---------
A 01-JUL-13
A 30-SEP-13
A 01-DEC-13
A 31-MAR-14
B 01-OCT-13
B 30-NOV-13
次に、外側のクエリはそれらの隣接するペアを折りたたみます。重複を作成してからdistinct
で削除するという簡単なルートを使用しました 、ただし、両方の値を行のペアの1つに入れ、両方の値をもう1つのnullのままにして、別のselectレイヤーでそれらを削除するなど、他の方法で行うこともできますが、ここでは区別しても問題ないと思います。
実際のユースケースに日付だけでなく時間が含まれている場合は、内部クエリで比較を調整する必要があります。 +/- 1ではなく、おそらく1秒の間隔、または必要に応じて1/86400ですが、値の精度によって異なります。