sql >> Databasteknik >  >> RDS >> Oracle

Uppdatera Trigger PL/SQL Oracle

Prova en sammansatt 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;
/

========REDIGERA - några frågor och svar ===========

F:Varför uppstår ett mutationstabellfel?
S:Detta beskrivs i dokumentationen:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

F:hur undviker man ett mutationstabellfel?
S:Dokumentationen rekommenderar användning av en coumpound-trigger, se detta:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

F:Vad är en sammansatt trigger och hur fungerar den?
S:Det här är ett stort ämne, vänligen se dokumentationen här:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

Kort sagt:detta är en speciell typ av trigger som gör det möjligt att kombinera fyra typer av separata triggers:BEFORE statement , BEFORE-for each row , AFTER for each row och AFTER statament till en en-deklaration. Det gör det lättare att implementera ett scenario där det finns ett behov av att överföra vissa data från en utlösare till en annan. Läs länken ovan för mer information.

F:Men vad gör egentligen "Departments( :new.department ) := :new.department; ?
S:Denna deklaration lagrar ett avdelningsnummer i en associativ array.

Denna array deklareras i en deklarativ del av den sammansatta triggern:

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

Dokumentationen relaterad till de sammansatta triggers säger att:http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

Ovanstående betyder att Departments variabeln initieras endast en gång i början av hela bearbetningen, precis efter att triggern utlöses. "Firing-state duration" betyder att denna variabel förstörs efter att triggern är klar.

Detta uttalande:Departments( :new.department ) := :new.department; lagrar ett avdelningsnummer i den associativa arrayen. Den finns i BEFORE EACH ROW sektionen, exekveras den för varje rad som uppdateras (eller infogas) av update/insert-satsen.

:new och :old är pseudorecords, mer om dem hittar du här: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Kort sagt::new.department hämtar ett nytt värde för department kolumn- för en för närvarande uppdaterad rad (uppdaterat värde - EFTER uppdateringen), medan :old.department ger ett gammalt värde för denna kolumn (INNAN uppdateringen).

Denna samling används senare i AFTER STATEMENT , när triggarna väljer alla uppdaterade avdelningar (i en FOR-LOOP), för varje avdelning avfyras SELECT SUM(salary) ... och kontrollerar sedan om denna summa är mindre än 1000

Tänk på en enkel uppdatering:UPDATE treballa SET salary = salary + 10 . Detta är ett enda uppdateringsuttryck, men ändrar många rader samtidigt. Ordningen för exekvering av vår trigger är följande:

  1. Uppdateringsstatistiken avfyras:UPDATE treballa SET salary = salary + 10
  2. Den deklarativa delen av utlösaren exekveras, det vill säga:Departments variabeln initieras
  3. BEFORE EACH ROW sektionen exekveras, separat för varje uppdaterad rad - så många gånger som det finns rader som ska uppdateras. På denna plats samlar vi alla avdelningar från ändrade rader.
  4. AFTER STATEMENT avsnittet utförs. Vid det här laget är tabellen redan uppdaterad - alla rader har redan nya, uppdaterade löner. Vi går igenom avdelningar sparade i Departments och för var och en kontrollerar vi om summan av löner är mindre eller lika med 1000. Om denna summa är> 1000 för någon av dessa avdelningar, så kastas ett fel, och hela uppdateringen avbryts och rullas tillbaka. Annars avslutas triggern och uppdateringen är klar (men du måste genomföra dessa ändringar ändå).

F:Vad är en associativ array, och varför används just den här typen av samling, snarare än andra samlingar (en varray eller en kapslad tabell) ?
S:PL/SQL-samlingar är ett stort ämne. Följ den här länken för att lära dig dem:http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

Kort sagt - Associativ array (eller index-by-tabell) är som en karta i java (hashmap, treemap etc) - det är en uppsättning nyckel-värdepar, och varje nyckel är unik . Du kan lägga samma nyckel många gånger i den här arrayen (med olika värden), men den här nyckeln kommer bara att lagras en gång - den är unik.
Jag har använt den för att få en unik uppsättning avdelningar.
Tänk på vårt uppdateringsexempel igen:UPDATE treballa SET salary = salary + 10 - detta kommando rör hundratals rader som har samma avdelning. Jag vill inte ha en samling med samma avdelning duplicerad 100 gånger, jag behöver en unik uppsättning avdelningar och jag vill köra vår fråga SELECT sum()... endast en gång för varje avdelning, inte 100 gånger. Med hjälp av den sssociativa arrayen görs det automatiskt - jag får en unik uppsättning avdelningar.




  1. TIMESTAMPDIFF i Oracle 11g?

  2. nollvärde undantag när du går in i databasen

  3. Hur hanterar man BLOB och CLOB i olingo v2?

  4. Ändra en primärnyckel till en sammansatt primärnyckel