SSJ Tech Lab - Oracle Database テクニカルラボ

日時とテーブル名を動的に指定して、データを削除するPL/SQL

対応バージョン

Oracle Database 11.2-12.1

2016-06-20記事公開

テーブルの削除ジョブなどを作成する場合に、テーブルの削除日やカラム名を動的に指定して作成したい場合に使用できるPL/SQLを紹介します。

データ準備

テーブル定義

削除内容を登録したマスタテーブルの定義

SQL> create user TEST identified by test default tablespace USERS;
SQL> grant CREATE SESSION to TEST;
SQL> grant UNLIMITED TABLESPACE to TEST;
SQL> grant CREATE TABLE to TEST;
SQL> conn test/test
SQL> create table MASTER_DEL_TABLE (
  2    TABLE_NAME       varchar2(30) -- 削除対象のテーブル名
  3  , COLUMN_NAME      varchar2(30) -- 削除対象のテーブルの指定カラム名(日付型を想定)
  4  , RETENTION_DAYS   number(4)    -- 削除対象となるテーブルの保存日数
  5  );

削除対象のテーブルの定義

SQL> create table TEST_TABLE (
  2    TESTID     number not null
  3  , UPDATED    date default sysdate
  4  );
SQL> -- データの登録はしないが、ループ確認用にテーブルを設定
SQL> create table ZAIKO (
  2    TESTID     number not null
  3  , HAIKI_DATE date default sysdate
  4  );

データ登録

削除対象のテーブルをマスタに登録

SQL> -- TEST_TABLE の UPDATED 列が、3日より前の場合は削除
SQL> insert into MASTER_DEL_TABLE values ('TEST_TABLE','UPDATED',3);
SQL> -- ダミーデータ(その他例として登録)
SQL> insert into MASTER_DEL_TABLE values ('ZAIKO','UPDATED',3);
SQL> commit;
SQL>
SQL> select * from MASTER_DEL_TABLE;

TABLE_NAME                     COLUMN_NAME                    RETENTION_DAYS
------------------------------ ------------------------------ --------------
TEST_TABLE                     UPDATED                                     3
ZAIKO                          HAIKI_DATE                                  3

SQL> -- 削除データについても登録
SQL> -- 4-5日前 削除対象
SQL> insert into TEST_TABLE values (1,sysdate - 5);
SQL> insert into TEST_TABLE values (2,sysdate - 4);
SQL> -- 当日-3日前 削除対象外
SQL> insert into TEST_TABLE values (3,sysdate - 3);
SQL> insert into TEST_TABLE values (4,sysdate - 2);
SQL> insert into TEST_TABLE values (5,sysdate - 1);
SQL> insert into TEST_TABLE values (6,sysdate - 0);
SQL> commit;
SQL> alter session set nls_date_format = 'yyyy/mm/dd hh24:mi:ss';
SQL> select * from TEST_TABLE order by 1;

    TESTID UPDATED
---------- -------------------
         1 2016/06/15 18:26:02
         2 2016/06/16 18:26:03
         3 2016/06/17 18:25:56
         4 2016/06/18 18:25:56
         5 2016/06/19 18:25:57
         6 2016/06/20 18:25:57

削除の実行

PL/SQLを実行しデータの削除を行います。

SQL> -- SQL エラーの場合は戻り値 2 で SQL*Plus を終了する
SQL> whenever sqlerror exit 2
SQL> -- OS エラーの場合は戻り値 2 で SQL*Plus を終了する
SQL> whenever oserror exit 2
SQL> set serveroutput on
SQL> DECLARE
  2    -- マスタからデータを取得するカーソルを定義
  3    CURSOR cDelMst IS
  4      select TABLE_NAME
  5           , COLUMN_NAME
  6           , RETENTION_DAYS
  7        from MASTER_DEL_TABLE;
  8    -- 一時的に SQL 文を格納する変数
  9    vSQL   VARCHAR2(4000);
 10
 11  BEGIN
 12    -- カーソルで指定したマスタデータをループし、1行ずつ処理を行う
 13    FOR vRec IN cDelMst LOOP
 14      -- 表名、列名は解析用に先に文字列化を行う。日付はバインド変数による実行計画対策。
 15      vSQL := 'DELETE FROM ' || vRec.TABLE_NAME || ' WHERE ' || vRec.COLUMN_NAME || ' < TRUNC(SYSDATE) - :1';
 16
 17      -- SQL 文を出力
 18      DBMS_OUTPUT.PUT_LINE('SQL=' || vSQL);
 19      DBMS_OUTPUT.PUT_LINE('Table=' || vRec.TABLE_NAME ||', Column='|| vRec.COLUMN_NAME ||', Days='|| vRec.RETENTION_DAYS);
 20
 21      -- SQL の実行
 22      EXECUTE IMMEDIATE vSQL
 23        USING IN vRec.RETENTION_DAYS;
 24
 25      COMMIT;
 26    END LOOP;
 27
 28  EXCEPTION
 29    WHEN NO_DATA_FOUND THEN
 30      -- 例外を無視
 31      DBMS_OUTPUT.PUT_LINE('NO_DATA_FOUND');
 32
 33    WHEN OTHERS THEN
 34      DBMS_OUTPUT.PUT_LINE('SQL Error: PL/SQLでエラーが発生しました。');
 35      RAISE;
 36  END;
 37  /
SQL=DELETE FROM TEST_TABLE WHERE UPDATED < TRUNC(SYSDATE) - :1
Table=TEST_TABLE, Column=UPDATED, Days=3
SQL=DELETE FROM ZAIKO WHERE HAIKI_DATE < TRUNC(SYSDATE) - :1
Table=ZAIKO, Column=HAIKI_DATE, Days=3

PL/SQL procedure successfully completed.

指定された期間が消えていることを確認します。TESTID 1と2(4日前と5日前)のデータが消えていることが確認出来ます。

SQL> select * from TEST_TABLE order by 1;

    TESTID UPDATED
---------- -------------------
         3 2016/06/17 18:25:57
         4 2016/06/18 18:25:57
         5 2016/06/19 18:25:57
         6 2016/06/20 18:25:57

上記でテーブルに保存した対象テーブルの指定期間のデータ削除ができるようになりました。
実際の運用で使用する場合は、エラーになったらその場で止まるなどするため、エラーケースを考えて実装してください。

関連記事

関連記事が存在しません