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

10-295 Overlapの解消

SQLパズル

tab1
d_begin  d_end
-------  -----
      1      2
      3      7  ←  3, 3 に変更
      4      7  ←  4, 6 に変更
      7      8  ←  7, 8 に変更
      7      9  ←  9, 9 に変更
      7     10  ← 10,10 に変更
      7    999  ← 11,19 に変更
     20     30

(1) 次の有効開始日が、自分の有効終了日と同じか古ければ
    自分の有効終了日を、次の有効開始日-1にします。
(2) 有効開始日が同じものがあれば、
    有効終了日の若い方をそのまま有効にし
    有効終了日の大きい方の有効開始日を、若い方の有効終了日+1 とします。
(3) 有効開始日と有効終了日が同じものは別途処理するものとします。

出力結果
d_begin  d_end
-------  -----
      1      2
      3      3
      4      6
      7      8
      9      9
     10     10
     11     19
     20     30

こちらを参考にさせていただきました


データ作成スクリプト

create table tab1 (
d_begin number(3),
d_end number(3));

insert into tab1 values(1,2);
insert into tab1 values(3,7);
insert into tab1 values(4,7);
insert into tab1 values(7,8);
insert into tab1 values(7,9);
insert into tab1 values(7,10);
insert into tab1 values(7,999);
insert into tab1 values(20,30);
commit;


SQL

select d_begin,d_end
  from (select Row_Number() over(order by d_begin,d_end) as Rn,
        d_begin,d_end
          from tab1)
 model
 dimension by (Rn)
 measures(d_begin,d_end)
 rules(d_end[Any] order by Rn = case when d_begin[CV()+1] <= d_end[CV()]
                                      and d_begin[CV()] != d_begin[CV()+1]
                                     then d_begin[CV()+1]-1
                                     else d_end[CV()] end,
       d_begin[Any] order by Rn = case when d_begin[CV()] <= d_end[CV()-1]
                                       then d_end[CV()-1]+1
                                       else d_begin[CV()] end);


解説

こういった再帰的な処理がある時には、model句が便利です。