トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
9-54 最大のリージョンを求める(境界あり)
SQLパズル
Seats4テーブル
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 空
D 16 空
D 17 空
D 18 空
D 19 空
Row_IDが同じで、Seatの昇順で、
Statusが最も長く連続して空なSeatを
以下の形式で出力する
出力結果
Row_ID SeatStart SeatEnd SeatCount
------ --------- ------- ---------
B 7 10 4
D 16 19 4
プログラマのためのSQL第2版の24章[リージョン、ラン、シーケンス]を参考にさせていただきました
データ作成スクリプト
create table Seats4 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
union select 'D',16,'空' from dual
union select 'D',17,'空' from dual
union select 'D',18,'空' from dual
union select 'D',19,'空' from dual;
SQL
--■■■lnnvl述語を使う方法■■■
select Row_ID,start_seat,end_seat,seat_cnt
from (select Row_ID,
min(座席) as start_seat,
max(座席) as end_seat,
count(*) as seat_cnt,
max(count(*)) over() as maxseat_cnt
from (select Row_ID,座席,
sum(willSum) over(partition by Row_ID order by 座席) as makeGroup
from (select Row_ID,座席,状態,
case when lnnvl(Lag(状態) over(partition by Row_ID order by 座席) = '空')
then 1 else 0 end as willSum
from Seats4)
where 状態 = '空')
group by Row_ID,makeGroup)
where seat_cnt = maxseat_cnt;
--■■■lnnvl述語を使わない方法■■■
select Row_ID,start_seat,end_seat,seat_cnt
from (select Row_ID,
min(座席) as start_seat,
max(座席) as end_seat,
count(*) as seat_cnt,
max(count(*)) over() as maxseat_cnt
from (select Row_ID,座席,
sum(willSum) over(partition by Row_ID order by 座席) as makeGroup
from (select Row_ID,座席,状態,
case when Lag(状態) over(partition by Row_ID order by 座席) = '空'
then 0 else 1 end as willSum
from Seats4)
where 状態 = '空')
group by Row_ID,makeGroup)
where seat_cnt = maxseat_cnt;
--■■■旅人算の感覚を使う方法■■■
select Row_ID,start_seat,end_seat,seat_cnt
from (select Row_ID,
min(座席) as start_seat,
max(座席) as end_seat,
count(*) as seat_cnt,
max(count(*)) over() as maxseat_cnt
from (select Row_ID,座席,状態,
Row_Number() over(partition by Row_ID order by 座席)
- Row_Number() over(partition by Row_ID,状態 order by 座席) as makeGroup
from Seats4)
where 状態 = '空'
group by Row_ID,makeGroup)
where seat_cnt = maxseat_cnt;
解説