Oracle
 sql >> база данни >  >> RDS >> Oracle

Задействане на Oracle след вмъкване или изтриване

Това, на което сте се сблъскали, е класическото изключение за "мутираща таблица". В ROW тригер Oracle не ви позволява да стартирате заявка към таблицата, върху която е дефиниран тригерът - така че това е SELECT срещу TABLE1 в DELETING част от спусъка, който причинява този проблем.

Има няколко начина да заобиколите това. Може би най-доброто в тази ситуация е да използвате комбиниран тригер, който би изглеждал нещо като:

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;

Съставният тригер позволява всяка времева точка (BEFORE STATEMENT , BEFORE ROW , AFTER ROW и AFTER STATEMENT ) да се обработва. Обърнете внимание, че точките за синхронизация винаги се извикват в дадения ред. Когато подходящ SQL израз (т.е. INSERT INTO TABLE1 или DELETE FROM TABLE1 ) се изпълнява и този тригер се задейства, първата времева точка, която трябва да бъде извикана, ще бъде BEFORE STATEMENT и кода в BEFORE STATEMENT манипулаторът ще разпредели PL/SQL таблица, за да съдържа куп числа. В този случай числата, които ще се съхраняват в таблицата PL/SQL, ще бъдат стойностите на TABLE2_ID от TABLE1. (Таблица PL/SQL се използва вместо, например, масив, защото таблицата може да съдържа различен брой стойности, докато ако използваме масив, ще трябва да знаем предварително колко числа ще трябва да съхраняваме. Не можем да знаем предварително колко реда ще бъдат засегнати от определен израз, затова използваме PL/SQL таблица).

Когато AFTER EACH ROW моментът е достигнат и откриваме, че операторът, който се обработва, е INSERT, тригерът просто продължава и извършва необходимото АКТУАЛИЗИРАНЕ на TABLE2, тъй като това няма да причини проблем. Въпреки това, ако се изпълнява DELETE, тригерът записва TABLE1.TABLE2_ID в PL/SQL таблицата, разпределена по-рано. Когато AFTER STATEMENT моментът на времето най-накрая е достигнат, PL/SQL таблицата, разпределена по-рано, се повтаря и за всеки намерен TABLE2_ID се извършва съответната актуализация.

Документация тук.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Функция NLS_CHARSET_NAME() в Oracle

  2. LISTAGG в Oracle за връщане на различни стойности

  3. Запомнете RAC екземпляри в Perf Tools

  4. Oracle:производителност на групово събиране

  5. Oracle - Как да получа действителния размер на конкретен РОД?