Това е проблем с пропуски и острови. Има различни начини за подход; това използва 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
Следващото ниво на избор премахва онези, които са в средата на периода, където и двете дати са празни от вътрешната заявка, което дава:
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
, но можете да го направите по други начини, като поставяне на двете стойности в една от двойките редове и оставяне на двете стойности в другата нула и след това елиминиране на тези с друг слой за избиране, но мисля, че distinct е ОК тук.
Ако вашият случай на използване в реалния свят има времена, а не само дати, тогава ще трябва да коригирате сравнението във вътрешната заявка; вместо +/- 1, може би интервал от 1 секунда или 1/86400, ако предпочитате, но зависи от точността на вашите стойности.