DBMS_SCHEDULER.DROP_JOB только если существует

У меня есть sql script, который я должен запустить после импорта дампа. среди прочего, script делает, он делает следующее:

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; 

Иногда работа была уже сброшена в исходной схеме, дамп приходит без задания, а script завершается с ошибкой:

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 

Как я могу избежать этого сбоя в случае, если задание не существует, но все же можно его удалить, если оно есть?

Ответ 1

Существует два основных шаблона, которые вы можете применить к обработке исключений; "Посмотрите, прежде чем прыгать" (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;

Стоит отметить две вещи об этом втором методе.

  • Я только поймаю ошибку, вызванную этим конкретным исключением. Можно было бы достичь того же, используя EXCEPTION WHEN OTHERS, но я бы очень рекомендовал против этого.

    Если вы обрабатываете исключение, вы должны точно знать, что вы собираетесь с ним делать. Маловероятно, что у вас есть возможность правильно обрабатывать каждое исключение Oracle с помощью OTHERS, и если вы это сделаете, вы, вероятно, должны регистрировать их где-нибудь, где они будут замечены. Чтобы указать из Oracle Рекомендации по устранению исключений и обработке исключений:

    Когда это возможно, напишите обработчики исключений для именованных исключений вместо использования обработчиков исключений OTHERS.

  • Oracle распространение исключений работает от внутреннего блока к внешнему блоку, поэтому исходной причиной ошибки станет первое исключение.