トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

5-65 連続した期間の抽出(OverLapを考慮せず)

SQLパズル

kikanT
ID  StaD        EndD
--  ----------  ----------
10  2010-06-01  2010-06-12
10  2010-06-13  2010-06-14
10  2010-06-15  null
20  2010-06-01  2010-06-11
20  2010-06-13  2010-06-15
50  2010-11-11  2010-11-13
50  2010-11-14  2010-11-20
50  2010-12-22  2010-12-30

IDごとで連続した期間をまとめる。
同じIDでの期間のOverLapは、存在しないものとする。

出力結果
ID  StaD        EndD
--  ----------  ----------
10  2010-06-01  null
20  2010-06-01  2010-06-11
20  2010-06-13  2010-06-15
50  2010-11-11  2010-11-20
50  2010-12-22  2010-12-30


データ作成スクリプト

create table kikanT(ID,StaD,EndD) as
select 10,date '2010-06-01',date '2010-06-12' from dual union
select 10,date '2010-06-13',date '2010-06-14' from dual union
select 10,date '2010-06-15',null              from dual union
select 20,date '2010-06-01',date '2010-06-11' from dual union
select 20,date '2010-06-13',date '2010-06-15' from dual union
select 50,date '2010-11-11',date '2010-11-13' from dual union
select 50,date '2010-11-14',date '2010-11-20' from dual union
select 50,date '2010-12-22',date '2010-12-30' from dual;


SQL

--■■■階層問い合わせを使う方法(10g以降)■■■
select ID,min(connect_by_root StaD) as StaD,EndD
  from kikanT
 where connect_by_IsLeaf = 1
connect by prior ID=ID
       and prior EndD+1=StaD
group by ID,EndD
order by ID,EndD;

--■■■分析関数を使う方法■■■
select ID,min(StaD) as StaD,
max(EndD) Keep(Dense_Rank Last order by EndD) as EndD
  from (select ID,StaD,EndD,
        sum(willSum) over(partition by ID order by StaD) as GID
        from (select ID,StaD,EndD,
              case when StaD = 1+Lag(EndD) over(partition by ID order by StaD)
                   then 0 else 1 end as willSum
                from kikanT))
group by ID,GID
order by ID,GID;


解説

分析関数を使う方法と、階層問い合わせを使う方法を
必要に応じて使い分けるいいでしょう。

9-3 開始日と終了日をまとめる
10-329 連続した範囲をまとめ、最も優先される期間を出力