web-dev-qa-db-ja.com

DBMS_SCHEDULER.DROP_JOBが存在する場合のみ

ダンプをインポートした後に実行する必要があるSQLスクリプトがあります。このスクリプトが実行する機能の中でも、次のことを実行します。

BEGIN 
--remove program          
SYS.DBMS_SCHEDULER.DROP_PROGRAM(program_name=>'STATISTICS_COLUMNS_PROG',FORCE=>TRUE);
--remove job
SYS.DBMS_SCHEDULER.DROP_JOB (job_name => 'STATISTICS_COLUMNS_JOB');
END; 

元のスキーマでジョブが既に削除されている場合、ダンプはジョブなしで来て、スクリプトは失敗します:

ERROR at line 1:
ORA-27475: "DMP_6633.STATISTICS_SET_COLUMNS_JOB" must be a job 
ORA-06512: at "SYS.DBMS_ISCHED", line 213 
ORA-06512: at "SYS.DBMS_SCHEDULER", line 657 
ORA-06512: at line 5 

ジョブが存在しないが、存在する場合でもそれをドロップできる場合に、どのようにこの失敗を回避できますか?

16
user2183505

例外処理に適用できる主なパターンは2つあります。 「飛ぶ前に見る」(LBYL)と「許可よりも赦しを求める方が簡単です」(EAFP)。 LBYLは、削除を試みる前にジョブが存在するかどうかを確認することを推奨します。 EAFPは、ジョブをドロップしようとし、発生した場合、その特定のエラーをキャプチャして無視することを伴います。

LBYLを適用する場合は、システムビュー USER_SCHEDULER_JOBS をクエリして、ジョブが存在するかどうかを確認できます。存在する場合は、ドロップします。

declare
   l_job_exists number;
begin
   select count(*) into l_job_exists
     from user_scheduler_jobs
    where job_name = 'STATISTICS_COLUMNS_JOB'
          ;

   if l_job_exists = 1 then
      dbms_scheduler.drop_job(job_name => 'STATISTICS_COLUMNS_JOB');
   end if;
end;

EAFPの場合は少し異なります。 独自の例外を定義する内部的に定義された例外に名前を付ける で、キャッチしようとしているエラーコードでインスタンス化するそのエラーが発生した場合、何もしません。

declare
   job_doesnt_exist EXCEPTION;
   PRAGMA EXCEPTION_INIT( job_doesnt_exist, -27475 );
begin
   dbms_scheduler.drop_job(job_name => 'STATISTICS_COLUMNS_JOB');
exception when job_doesnt_exist then
   null;
end;

この2番目の方法について2つの点に注目する価値があります。

  1. 私はonlyこの特定の例外によって発生したエラーをキャッチしています。 EXCEPTION WHEN OTHERSを使用して同じことを実現することは可能ですが、これを行うことを強くお勧めしますagainst

    例外を処理する場合は、例外をどうするかを正確に知っておく必要があります。 OTHERSを使用してすべてのOracle例外を適切に処理することができる可能性は低いため、そうする場合は、それらが気付く場所にログを記録する必要があります。 Oracleの 例外を回避および処理するためのガイドライン から引用するには:

    可能な限り、OTHERS例外ハンドラを使用する代わりに、名前付き例外の例外ハンドラを作成します。

  2. Oracleの 例外伝播 は、内部ブロックから外部ブロックに機能するため、エラーの元の原因は最初の例外になります。

40
Ben