sql >> Database >  >> RDS >> Oracle

Oracle-trigger na invoegen of verwijderen

Wat je bent tegengekomen is de klassieke uitzondering "mutating table". In een ROW-trigger staat Oracle niet toe dat u een query uitvoert op de tabel waarop de trigger is gedefinieerd - dus het is de SELECT tegen TABEL1 in de DELETING een deel van de trigger die dit probleem veroorzaakt.

Er zijn een aantal manieren om dit te omzeilen. Misschien is het in deze situatie het beste om een ​​samengestelde trigger te gebruiken, die er ongeveer zo uitziet:

CREATE OR REPLACE TRIGGER TABLE1_NUM_TRG
  FOR INSERT OR DELETE ON TABLE1
COMPOUND TRIGGER
  TYPE NUMBER_TABLE IS TABLE OF NUMBER;
  tblTABLE2_IDS  NUMBER_TABLE;

  BEFORE STATEMENT IS
  BEGIN
    tblTABLE2_IDS := NUMBER_TABLE();
  END BEFORE STATEMENT;

  AFTER EACH ROW IS
  BEGIN
    IF INSERTING THEN
      UPDATE TABLE2 t2
        SET    t2.TABLE2NUM = :new.NUM
        WHERE  t2.ID = :new.TABLE2_ID;
    ELSIF DELETING THEN
      tblTABLE2_IDS.EXTEND;
      tblTABLE2_IDS(tblTABLE2_IDS.LAST) := :new.TABLE2_ID;
    END IF;
  END AFTER EACH ROW;

  AFTER STATEMENT IS
  BEGIN
    IF tblTABLE2_IDS.COUNT > 0 THEN
      FOR i IN tblTABLE2_IDS.FIRST..tblTABLE2_IDS.LAST LOOP
        UPDATE TABLE2 t2
          SET t2.TABLE2NUM = (SELECT NUM
                                FROM (SELECT t1.NUM
                                        FROM TABLE1 t1
                                        WHERE t1.TABLE2_ID = tblTABLE2_IDS(i) 
                                        ORDER BY modification_date DESC)
                                WHERE ROWNUM = 1)
          WHERE t2.ID = tblTABLE2_IDS(i);
      END LOOP;
    END IF;
  END AFTER STATEMENT;
END TABLE1_NUM_TRG;

Een samengestelde trigger staat elk timingpunt toe (BEFORE STATEMENT , BEFORE ROW , AFTER ROW , en AFTER STATEMENT ) te behandelen. Merk op dat de timingpunten altijd in de aangegeven volgorde worden aangeroepen. Wanneer een geschikte SQL-instructie (d.w.z. INSERT INTO TABLE1 of DELETE FROM TABLE1 ) wordt uitgevoerd en deze trigger wordt geactiveerd. Het eerste timingpunt dat wordt aangeroepen is BEFORE STATEMENT , en de code in de BEFORE STATEMENT handler zal een PL/SQL-tabel toewijzen om een ​​aantal getallen te bevatten. In dit geval zijn de nummers die in de PL/SQL-tabel moeten worden opgeslagen, de TABLE2_ID-waarden uit TABLE1. (Er wordt een PL/SQL-tabel gebruikt in plaats van bijvoorbeeld een array omdat een tabel een wisselend aantal waarden kan bevatten, terwijl als we een array zouden gebruiken, we van tevoren zouden moeten weten hoeveel getallen we zouden moeten opslaan. We kunnen niet van tevoren weten hoeveel rijen worden beïnvloed door een bepaalde instructie, dus gebruiken we een PL/SQL-tabel).

Wanneer de AFTER EACH ROW timingpunt is bereikt en we ontdekken dat de instructie die wordt verwerkt een INSERT is, de trigger gaat gewoon door en voert de noodzakelijke UPDATE naar TABLE2 uit, omdat dit geen probleem zal veroorzaken. Als er echter een DELETE wordt uitgevoerd, slaat de trigger de TABLE1.TABLE2_ID op in de eerder toegewezen PL/SQL-tabel. Wanneer de AFTER STATEMENT timingpunt eindelijk is bereikt, wordt de eerder toegewezen PL/SQL-tabel doorlopen en wordt voor elke gevonden TABLE2_ID de juiste update uitgevoerd.

Documentatie hier.



  1. ORA-6502 met Grant Logging Trigger

  2. De Oracle Warehouse Builder 11g R2-client installeren

  3. Opgeslagen Oracle-procedure aanroepen met uitvoerparameter van SQL Server

  4. Omgaan met het maken van indexen met MongoEngine in Python