web-dev-qa-db-fra.com

DBMS_SCHEDULER.DROP_JOB uniquement s'il existe

J'ai un script SQL que je dois exécuter après avoir importé un vidage. entre autres choses le script fait, il fait ce qui suit:

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; 

Parfois, le travail a déjà été supprimé dans le schéma d'origine, le vidage est livré sans le travail et le script échoue:

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 

Comment puis-je éviter cet échec dans le cas où le travail n'existe pas mais peut encore le supprimer s'il l'est?

16
user2183505

Il existe deux modèles principaux que vous pouvez appliquer à la gestion des exceptions; "regarde avant de sauter" (LBYL) et "il est plus facile de demander pardon que de permission" (EAFP). LBYL recommanderait de vérifier si le travail existe avant d'essayer de le supprimer. EAFP impliquerait de tenter de supprimer le travail, puis de capturer et d'ignorer cette erreur spécifique, si elle se produit.

Si vous deviez appliquer LBYL, vous pouvez interroger la vue système USER_SCHEDULER_JOBS pour voir si votre travail existe. Si c'est le cas, laissez-le tomber.

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;

Pour l'EAFP, c'est légèrement différent; définir votre propre exception par nommer une exception définie en interne et l'instancier avec le code d'erreur que vous cherchez à détecter. Si cette erreur est ensuite déclenchée, ne faites rien.

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;

Il convient de noter deux choses à propos de cette deuxième méthode.

  1. Je suis seulement interceptant l'erreur soulevée par cette exception spécifique. Il serait possible de réaliser la même chose en utilisant EXCEPTION WHEN OTHERS mais je recommande fortement contre de faire cela.

    Si vous gérez une exception, vous devez savoir exactement ce que vous allez en faire. Il est peu probable que vous ayez la capacité de gérer correctement chaque exception Oracle en utilisant OTHERS et si vous le faites, vous devriez probablement les enregistrer quelque part où ils seront remarqués. Pour citer d'Oracle Directives pour éviter et gérer les exceptions :

    Dans la mesure du possible, écrivez des gestionnaires d'exceptions pour les exceptions nommées au lieu d'utiliser D'AUTRES gestionnaires d'exceptions.

  2. propagation d'exception d'Oracle fonctionne d'un bloc interne à un bloc externe, la cause d'origine de l'erreur sera donc la première exception.

40
Ben