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

10-102 ログテーブルの循環使用

SQLパズル

ログ履歴テーブル      当日ログテーブル
Seq  LogTxt           Seq  LogTxt
---  ---------        ---  ---------
  2  ログ履歴1         16  当日ログ1
  4  ログ履歴2         18  当日ログ2
  6  ログ履歴3         20  当日ログ3
  8  ログ履歴4         22  当日ログ4
 10  ログ履歴5         24  当日ログ5
 12  ログ履歴6
 14  ログ履歴7

当日ログテーブルのデータを、
ログ履歴テーブルに移し変える、
ただし、ログ履歴テーブルのデータは最大10件として、
10件を超えたらSeqが古いデータから上書きする。

更新結果
Seq  LogTxt
---  ---------
  6  ログ履歴3
  8  ログ履歴4
 10  ログ履歴5
 12  ログ履歴6
 14  ログ履歴7
 16  当日ログ1
 18  当日ログ2
 20  当日ログ3
 22  当日ログ4
 24  当日ログ5


データ作成スクリプト

create table ログ履歴(
Seq    number(4),
LogTxt varchar2(20));

insert into ログ履歴
select RowNum*2,'ログ履歴' || to_char(RowNum)
  from all_catalog
 where RowNum <= 7;

create table 当日ログ
as select * from ログ履歴
where RowNum = 0;

insert into 当日ログ
select RowNum*2+14,'当日ログ' || to_char(RowNum)
  from all_catalog
 where RowNum <= 5;
commit;


SQL

merge into ログ履歴 a
using(select Seq,LogTxt,Row_Number() over(order by Seq) as Rank
        from 当日ログ) b
on ((select count(*)+1
       from ログ履歴 c
      where c.Seq < a.Seq) = b.Rank + (select count(*) from ログ履歴) - 10)
when matched then
update set a.Seq= b.Seq,a.LogTxt=b.LogTxt
when not matched then
insert(a.Seq,a.LogTxt) values(b.Seq,b.LogTxt);


解説

on句で、
相関サブクエリで、順位を求めてます。

当日ログテーブルが11件以上のレコードを持つ場合は、
using句で、Seqの上位10件を抽出しておけばいいでしょう。