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

9-53 大きさNのリージョンを求める(境界あり)

SQLパズル

Seats3テーブル
Row_ID  Seat  Status
------  ----  ------
   A      1     占
   A      2     占
   A      3     空
   A      4     空
   A      5     空
   B      6     占
   B      7     空
   B      8     空
   B      9     空
   B     10     空
   C     11     空
   C     12     占
   C     13     占
   C     14     空
   C     15     空

Row_IDごとの、Seatの昇順で、Statusが3つ連続して、空
となるSeatを以下の形式で出力する

出力結果
Row_ID  SeatStart  SeatEnd
------  ---------  -------
   A       3          5
   B       7          9
   B       8         10
プログラマのためのSQL第2版の24章[リージョン、ラン、シーケンス]を参考にさせていただきました


データ作成スクリプト

create table Seats3 as
select 'A' as Row_ID,1 as 座席,'占' as 状態 from dual
union select 'A', 2,'占' from dual
union select 'A', 3,'空' from dual
union select 'A', 4,'空' from dual
union select 'A', 5,'空' from dual
union select 'B', 6,'占' from dual
union select 'B', 7,'空' from dual
union select 'B', 8,'空' from dual
union select 'B', 9,'空' from dual
union select 'B',10,'空' from dual
union select 'C',11,'空' from dual
union select 'C',12,'占' from dual
union select 'C',13,'占' from dual
union select 'C',14,'空' from dual
union select 'C',15,'空' from dual;


SQL

--■■■分析関数を使わない方法■■■
select a.座席 as SeatStart,b.座席 as SeatEnd
  from Seats3 a,Seats3 b
 where a.Row_ID = b.Row_ID
   and a.座席 < b.座席
   and exists(select 1 from Seats3 c
               where c.Row_ID = a.Row_ID
                 and c.座席 between a.座席 and b.座席
              having 3 = all(count(*),count(nullif(c.状態,'占'))));

--■■■分析関数を使う方法■■■
select SeatStart,SeatEnd
from (select 座席 as SeatStart,
      Lead(座席,3-1) over(partition by Row_ID order by 座席) as SeatEnd,
      count(nullif(状態,'占'))
      over(partition by Row_ID order by 座席
           Rows between current row and (3-1) following) as SeatCount
      from Seats3)
where SeatCount = 3;


解説

Count関数は、nullをカウントしないことと、
nullif関数を組み合わせてます。

マニュアル(分析関数)(英語)
マニュアル(分析関数)

CodeZine:SQLで数列を扱う
CodeZine:分析関数の衝撃(後編)