连续和非连续日期跨度中的Oracle SQL:找到的最早日期

问题描述:

我需要你的帮助来解决这个问题:连续和非连续日期跨度中的Oracle SQL:找到的最早日期

这里是我的数据

id  start_date end_date  
5567 2008-04-17 2008-04-30 
5567 2008-05-02 2008-07-31 
5567 2008-08-01 2008-08-31 
5567 2008-09-01 2009-12-31 

由于是2008-04之间的流逝-30和2008-05-02要求显示失效后的最早开始日期。

id  start_date end_date 
5567 2008-05-02 2008-08-31 

这里是另一个组数据:

id  start_date end_date 
5567 2008-04-17 2008-04-30 
5567 2008-05-01 2008-07-31 
5567 2008-08-01 2008-08-31 
5567 2008-09-01 2009-12-31 

在这种情况下,所有的跨度是连续的,从而所述的最早开始日期应该在输出。输出应该是:

id  start_date end_date 
5567 2008-04-17 2008-04-30 

这里是我使用的代码:当有失误

select 
id, min(start_date), contig 
from (
    select 
    id, start_date, end_date, 
    case 
    when lag(end_date) over (partition by id order by end_date) =  
    start_date-1 or row_number() over (partition by id order by  
    end_date)=1 
     then 'c' else 'l' end contig 
    from t2) 
group by id, contig; 

它的工作时,有跨度之间没有失误,但给两个记录。

例如,当跨度连续我的查询返回:

ID  MIN(START_DATE CONTIG 
5567 17-APR-08  c 

但是当数据是不连续它显示两条记录:

ID  MIN(START_DATE CONTIG 
5567 02-MAY-08  l 
5567 17-APR-08  c 

但在这种情况下,我只想要第一笔记录。

我知道有一个PL/SQL解决方案,但我可以在只有SQL中实现它吗? 数据库是Oracle 11gR2。

我认为这会做你想要什么:

select start_date 
from (select t2.start_date 
     from t2 left join 
      t2 t2p 
      on t2.start_date = t2p.end_date + 1 
     where t2p.end_date is null 
     order by t2.start_date nulls last 
    ) t 
where rownum = 1; 

您还可以lag()做到这一点:

select coalesce(min(case when prev_end_date is not null then start_date end), 
       min(start_date)) 
from (select t2.*, lag(t2.end_date) over (order by t2.start_date) as prev_end_date 
     from t2 
    ) t 
where prev_end_date is null or prev_end_date <> start_date - 1; 

你的 “其他” 条件是有点棘手。你必须小心,你一直没有得到最低开始日期。

+0

第二个解决方案就像一个魅力!感谢戈登您的时间和帮助! –