Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Update-Trigger PL/SQL Oracle

Versuchen Sie es mit einem zusammengesetzten Trigger:

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;
/

========BEARBEITEN - ein paar Fragen und Antworten ===========

F:Warum tritt ein Mutationstabellenfehler auf?
A:Dies ist in der Dokumentation beschrieben:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

F:Wie vermeide ich einen mutierenden Tabellenfehler?
A:Die Dokumentation empfiehlt die Verwendung eines Compound-Triggers, siehe hier:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

F:Was ist ein zusammengesetzter Trigger und wie funktioniert er?
A:Dies ist ein großes Thema, bitte lesen Sie die Dokumentation hier:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

Kurz gesagt:Dies ist eine spezielle Art von Trigger, die es ermöglicht, vier Arten von separaten Triggern zu kombinieren:BEFORE statement , BEFORE-for each row , AFTER for each row und AFTER statament in eine eine Deklaration. Es erleichtert die Implementierung einiger Szenarien, in denen einige Daten von einem Trigger an einen anderen übergeben werden müssen. Bitte studieren Sie den obigen Link für weitere Details.

F:Aber was bedeutet eigentlich "Departments( :new.department ) := :new.department; ?
A:Diese Deklaration speichert eine Abteilungsnummer in einem assoziativen Array.

Dieses Array wird in einem deklarativen Teil des zusammengesetzten Triggers deklariert:

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

Die Dokumentation zu den zusammengesetzten Triggern besagt Folgendes:http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

Das Obige bedeutet, dass Departments Die Variable wird nur einmal zu Beginn der gesamten Verarbeitung initialisiert, unmittelbar nachdem der Trigger ausgelöst wurde. "Auslöseanweisungsdauer" bedeutet, dass diese Variable zerstört wird, nachdem der Trigger beendet ist.

Diese Anweisung:Departments( :new.department ) := :new.department; speichert eine Abteilungsnummer im assoziativen Array. Es steht in BEFORE EACH ROW Abschnitt, dann wird es für jede Zeile ausgeführt, die durch die update/insert-Anweisung aktualisiert (oder eingefügt) wird.

:new und :old sind Pseudorecords, mehr dazu finden Sie hier: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Kurz::new.department ruft einen neuen Wert von department ab Spalte- für eine aktuell aktualisierte Zeile (aktualisierter Wert - NACH der Aktualisierung), während :old.department gibt einen alten Wert dieser Spalte an (VOR dem Update).

Diese Sammlung wird später im AFTER STATEMENT verwendet , wenn die Trigger alle aktualisierten Abteilungen (in einer FOR-LOOP) auswählen, wird für jede Abteilung SELECT SUM(salary) ... ausgelöst und prüft dann, ob diese Summe kleiner als 1000 ist

Erwägen Sie ein einfaches Update:UPDATE treballa SET salary = salary + 10 . Dies ist eine einzelne Update-Anweisung, ändert jedoch viele Zeilen auf einmal. Die Reihenfolge der Ausführung unseres Triggers ist wie folgt:

  1. Das Update-Statement wird ausgelöst:UPDATE treballa SET salary = salary + 10
  2. Der deklarative Abschnitt des Triggers wird ausgeführt, das heißt:Departments Variable wird initialisiert
  3. BEFORE EACH ROW Abschnitt ausgeführt wird, separat für jede aktualisierte Zeile - so oft, wie Zeilen zu aktualisieren sind. An dieser Stelle sammeln wir alle Abteilungen aus geänderten Reihen.
  4. AFTER STATEMENT Abschnitt ausgeführt wird. An dieser Stelle ist die Tabelle bereits aktualisiert – alle Zeilen haben bereits neue, aktualisierte Gehälter. Wir durchlaufen die Abteilungen, die in Departments gespeichert sind und für jede überprüfen wir, ob die Summe der Gehälter kleiner oder gleich 1000 ist. Wenn diese Summe für eine dieser Abteilungen> 1000 ist, wird ein Fehler ausgegeben, und die gesamte Aktualisierung wird abgebrochen und rückgängig gemacht. Andernfalls wird der Trigger beendet und die Aktualisierung durchgeführt (aber Sie müssen diese Änderungen trotzdem festschreiben).

F:Was ist ein assoziatives Array und warum wird gerade diese Art von Sammlung verwendet und nicht andere Sammlungen (ein varray oder eine verschachtelte Tabelle)?
A:PL/SQL-Sammlungen sind ein großes Thema. Folgen Sie diesem Link, um sie zu lernen:http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

Kurz gesagt - Assoziatives Array (oder Index-by-Tabelle) ist wie eine Karte in Java (Hashmap, Treemap usw.) - es ist ein Satz von Schlüssel-Wert-Paaren, und jeder Schlüssel ist einzigartig . Sie können denselben Schlüssel viele Male in dieses Array einfügen (mit unterschiedlichen Werten), aber dieser Schlüssel wird nur einmal gespeichert - er ist eindeutig.
Ich habe ihn verwendet, um einen eindeutigen Satz von Abteilungen zu erhalten.
Betrachten Sie noch einmal unser Update-Beispiel:UPDATE treballa SET salary = salary + 10 - Dieser Befehl berührt Hunderte von Zeilen, die dieselbe Abteilung haben. Ich möchte nicht, dass eine Sammlung mit derselben Abteilung 100 Mal dupliziert wird, ich brauche einen eindeutigen Satz von Abteilungen, und ich möchte unsere Abfrage SELECT sum()... ausführen nur einmal für jede Abteilung, nicht 100 Mal. Mit Hilfe des sssociative Arrays wird es automatisch gemacht - ich bekomme eindeutige Abteilungen.