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

5-60 having句でrank within

SQLパズル

dayTable
day1      Seq  Val
--------  ---  ----
20071201    1  AAAA
20071201    2  BBBB   ←出力対象
20071201    3  CCCC   ←出力対象
20071202    1  DDDD   ←出力対象
20071202    2  EEEE   ←出力対象
20071203    1  FFFF   ←出力対象
20071203    2  GGGG   ←出力対象
20071203    3  HHHH   ←出力対象
20071203    4  IIII   ←出力対象
20071204    1  JJJJ   ←出力対象
20071205    1  KKKK   ←出力対象
20071205    2  LLLL   ←出力対象
20071205    3  MMMM   ←出力対象
20071205    4  NNNN
20071206    1  OOOO

20071201のSeqが2の行から
20071205のSeqが3の行までのデータを出力する。


データ作成スクリプト

create table dayTable(day1,Seq,Val) as
select 20071201,1,'AAAA' from dual union
select 20071201,2,'BBBB' from dual union
select 20071201,3,'CCCC' from dual union
select 20071202,1,'DDDD' from dual union
select 20071202,2,'EEEE' from dual union
select 20071203,1,'FFFF' from dual union
select 20071203,2,'GGGG' from dual union
select 20071203,3,'HHHH' from dual union
select 20071203,4,'IIII' from dual union
select 20071204,1,'JJJJ' from dual union
select 20071205,1,'KKKK' from dual union
select 20071205,2,'LLLL' from dual union
select 20071205,3,'MMMM' from dual union
select 20071205,4,'NNNN' from dual union
select 20071206,1,'OOOO' from dual;


SQL

--■■■3つの条件に分けて、orを使う方法■■■
select day1,Seq,Val
  from dayTable
 where (day1 = 20071201 and 2 <= Seq)
    or day1 between 20071202 and 20071204
    or (day1 = 20071205 and Seq <= 3);

--■■■Rank関数を使う方法1■■■
select day1,Seq,Val
from (select day1,Seq,Val,
      Rank() over(order by day1,Seq) as Rank,
      sum(case when day1 < 20071201
                 or day1 = 20071201 and Seq <= 2
               then 1 else 0 end) over() as CompRank1,
      sum(case when day1 < 20071205
                 or day1 = 20071205 and Seq <= 3
               then 1 else 0 end) over() as CompRank2
        from dayTable)
where Rank between CompRank1 and CompRank2;

--■■■Rank関数を使う方法2■■■
select day1,Seq,Val
from (select day1,Seq,Val,Rank,
      max(case when day1 = 20071201 and Seq = 2 then Rank end) over() as CompRank1,
      max(case when day1 = 20071205 and Seq = 3 then Rank end) over() as CompRank2
      from (select day1,Seq,Val,
            Rank() over(order by day1,Seq) as Rank
              from dayTable))
where Rank between CompRank1 and CompRank2;

--■■■having句でrank withinを使う方法■■■
select day1,Seq,Val
  from dayTable a
 where exists(select 1
                from dayTable b
              having rank(a.day1,a.Seq) within group(order by b.day1,b.Seq)
             between rank(20071201,2)   within group(order by b.day1,b.Seq)
                 and rank(20071205,3)   within group(order by b.day1,b.Seq));


解説

7-40 指定した範囲のデータを取得
の類題です。

having句でrank withinを使う方法が分かりやすいと思います。