sql >> Databasteknik >  >> RDS >> Oracle

Oracle trigger efter infogning eller borttagning

Det du har stött på är det klassiska undantaget "muterande tabell". I en ROW-utlösare tillåter inte Oracle dig att köra en fråga mot tabellen som utlösaren är definierad på - så det är SELECT mot TABELL1 i DELETING del av utlösaren som orsakar det här problemet.

Det finns ett par sätt att kringgå detta. Det bästa i den här situationen är kanske att använda en sammansatt trigger, som skulle se ut ungefär så här:

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;

En sammansatt trigger tillåter varje tidpunkt (BEFORE STATEMENT , BEFORE ROW , AFTER ROW och AFTER STATEMENT ) som ska hanteras. Observera att tidpunkterna alltid åberopas i den ordning som anges. När en lämplig SQL-sats (dvs. INSERT INTO TABLE1 eller DELETE FROM TABLE1 ) exekveras och den här utlösaren aktiveras. Den första tidpunkten som ska anropas kommer att vara BEFORE STATEMENT , och koden i BEFORE STATEMENT hanteraren kommer att allokera en PL/SQL-tabell för att hålla ett gäng nummer. I detta fall kommer numren som ska lagras i PL/SQL-tabellen att vara TABLE2_ID-värdena från TABLE1. (En PL/SQL-tabell används istället för till exempel en array eftersom en tabell kan innehålla ett varierande antal värden, medan om vi använde en array skulle vi behöva veta i förväg hur många nummer vi skulle behöva lagra. Vi kan inte i förväg veta hur många rader som kommer att påverkas av en viss sats, så vi använder en PL/SQL-tabell).

När AFTER EACH ROW tidpunkten nås och vi finner att satsen som bearbetas är en INSERT, utlösaren går bara vidare och utför den nödvändiga UPPDATERING till TABELL2 eftersom detta inte kommer att orsaka några problem. Men om en DELETE utförs sparar triggern TABLE1.TABLE2_ID i PL/SQL-tabellen som allokerats tidigare. När AFTER STATEMENT tidpunkten nås äntligen, PL/SQL-tabellen som tilldelats tidigare itereras igenom, och för varje hittat TABLE2_ID utförs lämplig uppdatering.

Dokumentation här.



  1. Oändlig loop CTE med OPTION (maxrekursion 0)

  2. Kontrollera statusen för databasens e-postköer i SQL Server (T-SQL)

  3. Hur man använder Top with Ties i SQL Server - SQL Server / TSQL Tutorial Del 114

  4. skapa parametriserade vyer i oracle11g