sql >> Database teknologi >  >> RDS >> Oracle

Oracle-udløser efter indsættelse eller sletning

Det, du er stødt på, er den klassiske "mutationstabel"-undtagelse. I en ROW trigger tillader Oracle dig ikke at køre en forespørgsel mod den tabel, som triggeren er defineret på - så det er SELECT mod TABEL1 i DELETING del af udløseren, der forårsager dette problem.

Der er et par måder at omgå dette på. Måske er det bedste i denne situation at bruge en sammensat trigger, som ville se nogenlunde sådan ud:

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 sammensat trigger tillader hvert tidspunkt (BEFORE STATEMENT , BEFORE ROW , AFTER ROW , og AFTER STATEMENT ) skal håndteres. Bemærk, at tidspunkterne altid påberåbes i den angivne rækkefølge. Når en passende SQL-sætning (dvs. INSERT INTO TABLE1 eller DELETE FROM TABLE1 ) udføres, og denne udløser udløses, det første tidspunkt, der skal påkaldes, vil være BEFORE STATEMENT , og koden i BEFORE STATEMENT handler vil tildele en PL/SQL-tabel til at indeholde en masse tal. I dette tilfælde vil tallene, der skal gemmes i PL/SQL-tabellen, være TABLE2_ID-værdierne fra TABLE1. (En PL/SQL-tabel bruges i stedet for for eksempel en matrix, fordi en tabel kan indeholde et varierende antal værdier, mens hvis vi brugte en matrix, skulle vi på forhånd vide, hvor mange tal vi skal gemme. Vi kan ikke på forhånd vide, hvor mange rækker der vil blive påvirket af en bestemt sætning, så vi bruger en PL/SQL-tabel).

Når AFTER EACH ROW tidspunktet er nået, og vi finder ud af, at sætningen, der behandles, er en INSERT, triggeren går bare videre og udfører den nødvendige OPDATERING til TABLE2, da dette ikke vil forårsage et problem. Men hvis en DELETE udføres, gemmer triggeren TABLE1.TABLE2_ID i den tidligere tildelte PL/SQL-tabell. Når AFTER STATEMENT tidspunktet er endelig nået, den tidligere allokerede PL/SQL-tabell gentages, og for hver fundet TABLE2_ID udføres den passende opdatering.

Dokumentation her.



  1. Sådan sammenkædes strenge i SQL Server med CONCAT()

  2. Værdier vises ikke med indledende nul i oracle

  3. Indstilling af netværkstimeout for JDBC-forbindelse

  4. Tilføjelse af en kolonne som en fremmednøgle giver ERROR kolonne, der henvises til i fremmed nøgle begrænsning eksisterer ikke