トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
10-13 リニアサーチによる探索
SQLパズル
休館日テーブル 訪問予定日テーブル
day day
------------ ----------
2003/03/12 2003/03/11
2003/03/15 2003/03/15
2003/03/16 2003/03/17
2003/03/18 2003/03/20
2003/03/19 2003/03/25
2003/04/25 2003/04/25
上の2テーブルから
訪問予定日と訪問日(訪問予定日以降で休館日でない最小の日付)
を出力する。
出力結果
訪問予定日 訪問日
---------- ----------
2003/03/11 2003/03/11
2003/03/15 2003/03/17
2003/03/17 2003/03/17
2003/03/20 2003/03/20
2003/03/25 2003/03/25
2003/04/25 2003/04/26
データ作成スクリプト
create table 訪問予定日(day date);
create table 休館日(day date);
insert into 訪問予定日 values(to_date('20030311','yyyymmdd'));
insert into 訪問予定日 values(to_date('20030315','yyyymmdd'));
insert into 訪問予定日 values(to_date('20030317','yyyymmdd'));
insert into 訪問予定日 values(to_date('20030320','yyyymmdd'));
insert into 訪問予定日 values(to_date('20030325','yyyymmdd'));
insert into 訪問予定日 values(to_date('20030425','yyyymmdd'));
insert into 休館日 values(to_date('20030312','yyyymmdd'));
insert into 休館日 values(to_date('20030315','yyyymmdd'));
insert into 休館日 values(to_date('20030316','yyyymmdd'));
insert into 休館日 values(to_date('20030318','yyyymmdd'));
insert into 休館日 values(to_date('20030319','yyyymmdd'));
insert into 休館日 values(to_date('20030425','yyyymmdd'));
commit;
SQL
--■■■case式を使用■■■
select to_char(day,'yyyy/mm/dd') as 訪問予定日,
to_char(case when exists(select 1 from 休館日 b
where a.day=b.day)
then (select min(b.day) + 1 from 休館日 b
where b.day >= a.day
and not exists(select 1 from 休館日 c
where c.day = b.day+1))
else a.day end,'yyyy/mm/dd') as 訪問日
from 訪問予定日 a
order by 訪問予定日,訪問日;
--■■■decode関数を使用■■■
select to_char(day,'yyyy/mm/dd') as 訪問予定日,
to_char(decode((select count(*) from 休館日 b where a.day=b.day)
,1,(select min(b.day) + 1 from 休館日 b
where b.day >= a.day
and not exists(select 1 from 休館日 c
where c.day = b.day+1))
,a.day),'yyyy/mm/dd') as 訪問日
from 訪問予定日 a
order by 訪問予定日,訪問日;
--■■■分析関数を使用■■■
select to_char(訪問予定日,'yyyy/mm/dd') as 訪問予定日,
to_char(
case willSeek when 1 then min(kouho)
else 訪問予定日 end,'yyyy/mm/dd') as 訪問日
from (select a.day as 訪問予定日,
case a.day when min(b.day) over(partition by a.day)
then 1 else 0 end as willSeek,
nullIf(b.day+1,Lead(b.day)
over(partition by a.day
order by b.day)) as kouho
from 訪問予定日 a,休館日 b
where a.day <= b.day)
group by 訪問予定日,willSeek
order by 訪問予定日;
解説
第一候補の日に訪問可能かを調べて、
訪問可能の場合は、その日となります。
第一候補の日に訪問不可の場合は、休館日が最大のデータを番兵とした、
第一候補以降で訪問可能な日の探索を行います。