Apa yang Anda temui adalah pengecualian klasik "tabel bermutasi". Dalam pemicu ROW, Oracle tidak mengizinkan Anda menjalankan kueri terhadap tabel tempat pemicu didefinisikan - jadi ini adalah SELECT
terhadap TABEL1 di DELETING
bagian dari pemicu yang menyebabkan masalah ini.
Ada beberapa cara untuk mengatasi hal ini. Mungkin yang terbaik dalam situasi ini adalah menggunakan pemicu majemuk, yang akan terlihat seperti:
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;
Pemicu gabungan memungkinkan setiap titik waktu (BEFORE STATEMENT
, BEFORE ROW
, AFTER ROW
, dan AFTER STATEMENT
) untuk ditangani. Perhatikan bahwa titik waktu selalu dipanggil dalam urutan yang diberikan. Ketika pernyataan SQL yang sesuai (yaitu INSERT INTO TABLE1
atau DELETE FROM TABLE1
) dieksekusi dan pemicu ini dipicu, titik waktu pertama yang dipanggil adalah BEFORE STATEMENT
, dan kode di BEFORE STATEMENT
handler akan mengalokasikan tabel PL/SQL untuk menampung banyak angka. Dalam hal ini angka yang akan disimpan dalam tabel PL/SQL akan menjadi nilai TABLE2_ID dari TABLE1. (Tabel PL/SQL digunakan sebagai pengganti, misalnya, array karena tabel dapat menampung sejumlah nilai yang bervariasi, sedangkan jika kita menggunakan array, kita harus mengetahui terlebih dahulu berapa banyak angka yang perlu kita simpan. Kami tidak dapat mengetahui sebelumnya berapa banyak baris yang akan terpengaruh oleh pernyataan tertentu, jadi kami menggunakan tabel PL/SQL).
Ketika AFTER EACH ROW
titik waktu tercapai dan kami menemukan bahwa pernyataan yang sedang diproses adalah INSERT, pemicunya terus maju dan melakukan UPDATE yang diperlukan ke TABLE2 karena ini tidak akan menyebabkan masalah. Namun, jika DELETE sedang dilakukan, pemicu menyimpan TABLE1.TABLE2_ID ke dalam tabel PL/SQL yang dialokasikan sebelumnya. Ketika AFTER STATEMENT
titik waktu akhirnya tercapai, tabel PL/SQL yang dialokasikan sebelumnya diulang, dan untuk setiap TABLE2_ID yang ditemukan, pembaruan yang sesuai dilakukan.
Dokumentasi di sini.