Oracle
 sql >> Base de données >  >> RDS >> Oracle

Mettre à jour le déclencheur PL/SQL Oracle

Essayez un déclencheur composé :

CREATE OR REPLACE TRIGGER compound_trigger_name
FOR  INSERT OR UPDATE OF salary ON treballa
COMPOUND TRIGGER

  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;

     BEFORE EACH ROW IS
     BEGIN
        -- collect updated or inserted departments 
        Departments( :new.department ) := :new.department;
     END BEFORE EACH ROW;

     AFTER STATEMENT IS
        sum_sal NUMBER;
     BEGIN
      -- for each updated department check the restriction
      FOR dept IN Departments.FIRST .. Departments.LAST
      LOOP
         SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
         IF sum_sal > 1000 THEN
            raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
         END IF;
      END LOOP;
     END AFTER STATEMENT;

END compound_trigger_name;
/

========EDIT - quelques questions et réponses ===========

Q :Pourquoi une erreur de table en mutation se produit-elle ?
R :Ceci est décrit dans la documentation :
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

Q :comment éviter une erreur de table en mutation ?
R :La documentation recommande l'utilisation d'un déclencheur composé, voir ceci :http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

Q :Qu'est-ce qu'un déclencheur composé et comment fonctionne-t-il ?
R :C'est un vaste sujet, veuillez consulter la documentation ici :http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

En bref :il s'agit d'un type spécial de déclencheur qui permet de combiner quatre types de déclencheurs distincts :BEFORE statement , BEFORE-for each row , AFTER for each row et AFTER statament en une seule déclaration. Cela facilite la mise en œuvre de certains scénarios dans lesquels il est nécessaire de transmettre certaines données d'un déclencheur à un autre. Veuillez étudier le lien ci-dessus pour plus de détails.

Q :Mais que signifie réellement "Departments( :new.department ) := :new.department; ?
A :Cette déclaration stocke un numéro de service dans un tableau associatif.

Ce tableau est déclaré dans une partie déclarative du déclencheur composé :

  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;

La documentation relative aux déclencheurs composés indique que :http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

Ce qui précède signifie que Departments La variable est initialisée une seule fois au début de l'ensemble du traitement, juste après le déclenchement du déclencheur. "Firing-statement duration" signifie que cette variable est détruite après la fin du déclencheur.

Cette instruction :Departments( :new.department ) := :new.department; stocke un numéro de département dans le tableau associatif. C'est dans BEFORE EACH ROW section, puis elle est exécutée pour chaque ligne mise à jour (ou insérée) par l'instruction update/insert.

:new et :old sont des pseudo-enregistrements, vous pouvez en trouver plus ici : http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
En bref ::new.department récupère une nouvelle valeur de department colonne - pour une ligne actuellement mise à jour (valeur mise à jour - APRÈS la mise à jour), tandis que :old.department donne une ancienne valeur de cette colonne (AVANT la mise à jour).

Cette collection est ensuite utilisée dans le AFTER STATEMENT , lorsque les déclencheurs sélectionnent tous les départements mis à jour (dans une boucle FOR), pour chaque département déclenche SELECT SUM(salary) ... et vérifie ensuite si cette somme est inférieure à 1000

Envisagez une simple mise à jour :UPDATE treballa SET salary = salary + 10 . Il s'agit d'une instruction de mise à jour unique, mais modifie plusieurs lignes à la fois. L'ordre d'exécution de notre trigger est le suivant :

  1. L'état de mise à jour est déclenché :UPDATE treballa SET salary = salary + 10
  2. La section déclarative du déclencheur est exécutée, c'est-à-dire :Departments la variable est initialisée
  3. BEFORE EACH ROW section est exécutée, séparément pour chaque ligne mise à jour - autant de fois qu'il y a de lignes à mettre à jour. À cet endroit, nous collectons tous les départements des lignes modifiées.
  4. AFTER STATEMENT section est exécutée. À ce stade, le tableau est déjà mis à jour - toutes les lignes ont déjà de nouveaux salaires mis à jour. Nous parcourons les départements enregistrés dans Departments et pour chacun, nous vérifions si la somme des salaires est inférieure ou égale à 1000. Si cette somme est> 1000 pour l'un de ces départements, une erreur est renvoyée et toute la mise à jour est annulée et annulée. Sinon, le déclencheur se termine et la mise à jour est terminée (mais vous devez quand même valider ces modifications).

Q :Qu'est-ce qu'un tableau associatif et pourquoi ce type de collection est-il utilisé plutôt que d'autres collections (un varray ou une table imbriquée) ?
R :Les collections PL/SQL sont un vaste sujet. Suivez ce lien pour les apprendre :http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

En bref - Un tableau associatif (ou une table indexée) est comme une carte en Java (hashmap, treemap, etc.) - c'est un ensemble de paires clé-valeur, et chaque clé est uniques . Vous pouvez mettre la même clé plusieurs fois dans ce tableau (avec des valeurs différentes), mais cette clé ne sera stockée qu'une seule fois - elle est unique.
Je l'ai utilisée pour obtenir un ensemble unique de départements.
Reprenons notre exemple de mise à jour :UPDATE treballa SET salary = salary + 10 - cette commande touche des centaines de lignes qui ont le même département. Je ne veux pas qu'une collection avec le même département soit dupliquée 100 fois, j'ai besoin d'un ensemble unique de départements, et je veux exécuter notre requête SELECT sum()... une seule fois pour chaque département, pas 100 fois. Avec l'aide du tableau sssociatif, cela se fait automatiquement - j'obtiens un ensemble unique de départements.