フラッシュバッククエリーに関する検証 その4

~フラッシュバッククエリーに関する検証 その4 ~
ペンネーム ちゃむ

前回は、フラッシュバッククエリーで実際に1時間前のデータを取得できる様子
を示した。但し、データをテーブルなどに格納しようとすると、以下のように、
SQL*PLUSより実行してORA-08182が発生してしまった。

SQL> alter session set NLS_TIMESTAMP_FORMAT = 'yyyy/mm/dd hh24:mi:ss';
Session altered.
SQL>  execute dbms_flashback.enable_at_time('2001/12/26 12:54:44');
PL/SQL procedure successfully completed.
SQL> insert into b select * from a;
ORA-08182: operation not supported while in Flashback mode

今回は、このフラッシュバッククエリーで検索したデータをテーブル
などに格納する方法を説明する。また、オブジェクトの定義が変わってしまっ
たときには、どうなるのかも検証してみる。

それを実現するために使用するのは、超定番のPL/SQLである。
ポイントは、DBMS_FLASHBACK.enable_at_timeで時間してした後、カーソルに
そのデータを事前に格納しておくことと、更新処理(今回はINSERT文)を実行する前に
DBMS_FLASHBACK.DISABLE;でフラッシュバッククエリーを無効にすることである。

<PL/SQLで実現!!>

1.既にテーブルAという14行のデータが存在することを確認し、事前に空のテ
ーブルBを作成しておく。

SQL> SELECT COUNT(*) FROM A;

  COUNT(*)
----------
        14

SQL> CREATE TABLE B AS SELECT * FROM A WHERE 1=2;
Table created.

SQL> SELECT COUNT(*) FROM B;
  COUNT(*)
----------
         0

2.以下のPL/SQLブロックをそのまま、SQL*PLUSにコピー&ペーストで実行してみる。

------------------------ PL/SQLブロック ------------------------

DECLARE
    cursor A_CUR  is  SELECT  * FROM A;
    A_DATA  A_CUR%rowtype;
BEGIN

DBMS_FLASHBACK.enable_at_time(to_timestamp('2001/12/26 12:54:44', 'YYYY-MM-DD HH24:MI:SS'));
/* DBMS_FLASHBACK.DISABLEをする前にカーソルをオープンしておくこと*/
OPEN A_CUR;
/*INSERT 処理を行なう前に、フラッシュバッククエリーを無効にする*/
DBMS_FLASHBACK.DISABLE;

LOOP
   FETCH A_CUR INTO A_DATA;
   EXIT WHEN A_CUR%NOTFOUND;
   INSERT INTO B VALUES(A_DATA.EMPNO,A_DATA.ENAME,A_DATA.JOB,A_DATA.MGR,
                       A_DATA.HIREDATE,A_DATA.SAL,A_DATA.COMM,A_DATA.DEPTNO);
END LOOP;

COMMIT;
END;
/
------------------------ PL/SQLブロック ------------------------

PL/SQL procedure successfully completed.

3.テーブルBのデータの中身を確認

SQL> SELECT COUNT(*) FROM  B;

  COUNT(*)
----------
        14

フラッシュバッククエリーの結果を別テーブルに格納できた!!
この機能を使えば、同じテーブルの現在のデータと過去のデータの
比較などもできることが想像つくであろう。

<オブジェクトの定義が変わってしまったとき>

さて、話は変わるが、テーブルが存在しないときや定義を変更してしまった場合は、
どうなるのであろうか?結果から言うとエラーが発生する。つまり、DROP TABLEして
しまった場合、フラッシュバッククエリーでは、残念ながらデータを取得できない。
ログマイナーであればORACLE9iのサプリメンタル・ロギングの機能を使用していれば、
DROP TABLEしたテーブルでも復旧できる。詳しくは、ログマイナに関する検証
その六をご覧いただきたい。

<テーブルが既にドロップされてしまった場合>

SQL> drop table a;
SQL> create table a as select * from emp where 1=2;

SQL>  alter session set NLS_TIMESTAMP_FORMAT = 'yyyy/mm/dd hh24:mi:ss';
Session altered.
SQL> execute dbms_flashback.enable_at_time('2001/12/26 12:54:44');
PL/SQL procedure successfully completed.
SQL> select count(*) from a;
ORA-00942: table or view does not exist

<テーブルの定義が変更された場合>

SQL>  alter session set NLS_TIMESTAMP_FORMAT = 'yyyy/mm/dd hh24:mi:ss';
Session altered.
SQL> execute dbms_flashback.enable_at_time('2001/12/26 12:54:44');
PL/SQL procedure successfully completed.
SQL> select count(*) from a;
ORA-01466: unable to read data - table definition has changed

以上 苦しいときも、悲しいときも 茅ケ崎にて