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

7-5 同一日付を期間に含むレコード数

SQLパズル

期間テーブル
NO   FromTime     ToTime
--   ----------   ----------
 1   2005-08-01   2005-08-03
 2   2005-08-05   2005-08-10
 3   2005-08-07   2005-08-15
 4   2005-08-08   2005-08-13
 5   2005-08-17   2005-08-25

期間テーブルのレコードで、
8/8を期間に含むレコード数は、3で、
8/15を期間に含むレコード数は、1となってます。

このテーブルに新たに期間データを登録する。
ただし、日付ごとの、同一日付を期間に含むレコード数が、3を超えてしまう場合は登録しない


データ作成スクリプト

create table 期間(
NO       number(1),
FromTime date,
ToTime   date);

insert into 期間 values(1,to_date('20050801','yyyymmdd'),to_date('20050803','yyyymmdd'));
insert into 期間 values(2,to_date('20050805','yyyymmdd'),to_date('20050810','yyyymmdd'));
insert into 期間 values(3,to_date('20050807','yyyymmdd'),to_date('20050815','yyyymmdd'));
insert into 期間 values(4,to_date('20050808','yyyymmdd'),to_date('20050813','yyyymmdd'));
insert into 期間 values(5,to_date('20050817','yyyymmdd'),to_date('20050825','yyyymmdd'));
commit;


SQL

--■■■FromTimeが8/8、ToTimeが8/10(insert不可)■■■
insert into 期間(NO,FromTime,ToTime)
select 6,to_date('20050808','yyyymmdd'),to_date('20050810','yyyymmdd') from dual
where
(select max(count(*))
   from 期間 a,
        (select to_date('20050808','yyyymmdd')+RowNum as 日付
           from all_catalog
          where to_date('20050808','yyyymmdd')+RowNum <= to_date('20050810','yyyymmdd')) b
  where b.日付 between a.FromTime and a.ToTime
 group by b.日付) < 3;

--■■■FromTimeが8/15、ToTimeが8/25(insert可)■■■
insert into 期間(NO,FromTime,ToTime)
select 6,to_date('20050815','yyyymmdd'),to_date('20050825','yyyymmdd') from dual
where
(select max(count(*))
   from 期間 a,
        (select to_date('20050815','yyyymmdd')+RowNum as 日付
           from all_catalog
          where to_date('20050815','yyyymmdd')+RowNum <= to_date('20050825','yyyymmdd')) b
  where b.日付 between a.FromTime and a.ToTime
 group by b.日付) < 3;


解説

サブクエリを使って、
FromTimeからToTimeまでの各日付を期間に含むレコード数をチェックしてます。

insert時にチェックするので、
ファントムリードやアンリピータブルリードが発生しづらくなります。

トランザクションの並列処理時に発生する問題

RowNum指定によるCountStopの資料