sql >> Database >  >> RDS >> Oracle

Update Trigger PL/SQL Oracle

Probeer een samengestelde 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;
/

========BEWERKEN - een paar vragen en antwoorden ===========

V:Waarom treedt er een muterende tabelfout op?
A:Dit wordt beschreven in de documentatie:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

V:hoe kan ik een muterende tabelfout vermijden?
A:De documentatie beveelt het gebruik van een samengestelde trigger aan, zie deze:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

V:Wat is een samengestelde trigger en hoe werkt het?
A:Dit is een enorm onderwerp, raadpleeg de documentatie hier:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

Kortom:dit is een speciaal soort trigger die het mogelijk maakt om vier soorten afzonderlijke triggers te combineren:BEFORE statement , BEFORE-for each row , AFTER for each row en AFTER statament in één aangifte. Het maakt het gemakkelijker om een ​​aantal scenario's te implementeren waarin het nodig is om bepaalde gegevens van de ene trigger naar de andere door te geven. Bekijk de bovenstaande link voor meer details.

V:Maar wat doet "Departments( :new.department ) := :new.department; eigenlijk? ?
A:Deze declaratie slaat een afdelingsnummer op in een associatieve array.

Deze array wordt gedeclareerd in een declaratief deel van de samengestelde trigger:

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

De documentatie met betrekking tot de samengestelde triggers zegt dat:http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

Het bovenstaande betekent dat Departments variabele wordt slechts één keer geïnitialiseerd aan het begin van de hele verwerking, net nadat de trigger is geactiveerd. "Firing-statement duration" betekent dat deze variabele wordt vernietigd nadat de trigger is voltooid.

Deze instructie:Departments( :new.department ) := :new.department; slaat een afdelingsnummer op in de associatieve array. Het staat in BEFORE EACH ROW sectie, dan wordt het uitgevoerd voor elke rij die is bijgewerkt (of ingevoegd) door de update/insert-instructie.

:new en :old zijn pseudorecords, meer hierover kun je hier vinden: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Kortom::new.department haalt een nieuwe waarde op van department kolom- voor een momenteel bijgewerkte rij (bijgewerkte waarde - NA de update), terwijl :old.department geeft een oude waarde van deze kolom (VOOR de update).

Deze verzameling wordt later gebruikt in de AFTER STATEMENT , wanneer de triggers alle bijgewerkte afdelingen kiezen (in een FOR-LOOP), vuren voor elke afdeling SELECT SUM(salary) ... en controleert dan of dit bedrag kleiner is dan 1000

Overweeg een simpele update:UPDATE treballa SET salary = salary + 10 . Dit is een enkele update-instructie, maar verandert veel rijen tegelijk. De volgorde van uitvoering van onze trigger is als volgt:

  1. De update-verklaring is geactiveerd:UPDATE treballa SET salary = salary + 10
  2. Het declaratieve gedeelte van de trigger wordt uitgevoerd, dat wil zeggen:Departments variabele is geïnitialiseerd
  3. BEFORE EACH ROW sectie wordt uitgevoerd, afzonderlijk voor elke bijgewerkte rij - zo vaak als er rijen zijn die moeten worden bijgewerkt. Op deze plaats verzamelen we alle afdelingen van gewijzigde rijen.
  4. AFTER STATEMENT sectie wordt uitgevoerd. Op dit punt is de tabel al bijgewerkt - alle rijen hebben al nieuwe, bijgewerkte salarissen. We doorlopen afdelingen die zijn opgeslagen in Departments en voor elk controleren we of de som van de salarissen kleiner of gelijk is aan 1000. Als deze som> 1000 is voor een van deze afdelingen, wordt er een fout gegenereerd en wordt de hele update afgebroken en teruggedraaid. Anders wordt de trigger voltooid en is de update voltooid (maar u moet deze wijzigingen toch vastleggen).

V:Wat is een associatieve array en waarom wordt juist dit soort verzameling gebruikt in plaats van andere verzamelingen (een varray of een geneste tabel)?
A:PL/SQL-collecties zijn een groot onderwerp. Volg deze link om ze te leren:http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

Kortom - Associatieve array (of index-by-tabel) is als een map in Java (hashmap, treemap, enz.) - het is een set sleutel-waardeparen en elke sleutel is uniek . Je kunt dezelfde sleutel meerdere keren in deze array plaatsen (met verschillende waarden), maar deze sleutel wordt maar één keer opgeslagen - het is uniek.
Ik heb het gebruikt om een ​​unieke set afdelingen te krijgen.
Bekijk ons ​​updatevoorbeeld nog eens:UPDATE treballa SET salary = salary + 10 - dit commando raakt honderden rijen die dezelfde afdeling hebben. Ik wil niet dat een verzameling met dezelfde afdeling 100 keer wordt gedupliceerd, ik heb een unieke set afdelingen nodig en ik wil onze query uitvoeren SELECT sum()... slechts één keer voor elke afdeling, niet 100 keer. Met behulp van de sssociative array wordt dit automatisch gedaan - ik krijg een unieke set afdelingen.




  1. Hoe kan ik een asynchrone oproep afronden om zich synchroon te gedragen?

  2. Tijd toevoegen aan DateTime in SQL

  3. Is het sorteren van InnoDB echt ZO traag?

  4. SQL in vs intersectie