Coba pemicu majemuk:
CREATE OR REPLACE TRIGGER compound_trigger_name
FOR INSERT OR UPDATE OF salary ON treballa
COMPOUND TRIGGER
TYPE Departments_t IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
Departments Departments_t;
BEFORE EACH ROW IS
BEGIN
-- collect updated or inserted departments
Departments( :new.department ) := :new.department;
END BEFORE EACH ROW;
AFTER STATEMENT IS
sum_sal NUMBER;
BEGIN
-- for each updated department check the restriction
FOR dept IN Departments.FIRST .. Departments.LAST
LOOP
SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
IF sum_sal > 1000 THEN
raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
END IF;
END LOOP;
END AFTER STATEMENT;
END compound_trigger_name;
/
========EDIT - beberapa pertanyaan dan jawaban ===========
T:Mengapa terjadi kesalahan tabel mutasi ?
J:Ini dijelaskan dalam dokumentasi:
http://docs.Oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708
T:bagaimana cara menghindari kesalahan mutasi tabel ?
J:Dokumentasi merekomendasikan penggunaan pemicu coumpound, lihat ini:http://docs.Oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ
T:Apa yang dimaksud dengan pemicu majemuk dan bagaimana cara kerjanya ?
J:Ini adalah topik besar, silakan lihat dokumentasi di sini:http://docs.Oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD
Singkatnya:ini adalah jenis pemicu khusus yang memungkinkan untuk menggabungkan empat jenis pemicu terpisah:BEFORE statement
, BEFORE-for each row
, AFTER for each row
dan AFTER statament
menjadi satu deklarasi. Itu memudahkan untuk mengimplementasikan beberapa skenario di mana ada kebutuhan untuk melewatkan beberapa data dari satu pemicu ke pemicu lainnya. Silakan pelajari tautan di atas untuk detail lebih lanjut.
T:Tapi apa sebenarnya "Departments( :new.department ) := :new.department;
?
A:Deklarasi ini menyimpan nomor departemen ke dalam array asosiatif.
Array ini dideklarasikan di bagian deklaratif dari pemicu gabungan:
TYPE Departments_t IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
Departments Departments_t;
Dokumentasi yang terkait dengan pemicu senyawa mengatakan bahwa:http ://docs.Oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE
Di atas berarti Departments
variabel diinisialisasi hanya sekali pada awal seluruh pemrosesan, tepat setelah pemicu diaktifkan. "Durasi pernyataan pengaktifan" berarti variabel ini dimusnahkan setelah pemicu selesai.
Pernyataan ini:Departments( :new.department ) := :new.department;
menyimpan nomor departemen dalam array asosiatif. Itu ada di BEFORE EACH ROW
bagian, kemudian dieksekusi untuk setiap baris yang diperbarui (atau disisipkan) oleh pernyataan update/insert.:new
dan :old
adalah pseudorecords, lebih banyak tentang mereka dapat Anda temukan di sini: http://docs.Oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Singkatnya::new.department
mengambil nilai baru department
kolom- untuk baris yang saat ini diperbarui (nilai yang diperbarui - SETELAH pembaruan), sedangkan :old.department
memberikan nilai lama dari kolom ini (SEBELUM update).
Koleksi ini kemudian digunakan dalam AFTER STATEMENT
, ketika pemicu memilih semua departemen yang diperbarui (dalam FOR-LOOP), untuk setiap departemen akan mengaktifkan SELECT SUM(salary) ...
dan kemudian memeriksa apakah jumlah ini kurang dari 1000
Pertimbangkan pembaruan sederhana:UPDATE treballa SET salary = salary + 10
. Ini adalah pernyataan pembaruan tunggal, tetapi mengubah banyak baris sekaligus. Urutan eksekusi pemicu kami adalah sebagai berikut:
- Pernyataan pembaruan dipecat:
UPDATE treballa SET salary = salary + 10
- Bagian deklaratif pemicu dijalankan, yaitu:
Departments
variabel diinisialisasi BEFORE EACH ROW
bagian dijalankan, secara terpisah untuk setiap baris yang diperbarui - sebanyak baris yang akan diperbarui. Di tempat ini kami mengumpulkan semua departemen dari baris yang diubah.AFTER STATEMENT
bagian dijalankan. Pada titik ini tabel sudah diperbarui - semua baris sudah memiliki gaji baru yang diperbarui. Kami mengulang departemen yang disimpan diDepartments
dan untuk masing-masing departemen kami memeriksa apakah jumlah gaji kurang atau sama dengan 1000. Jika jumlah ini> 1000 untuk salah satu departemen ini, maka kesalahan akan terjadi, dan seluruh pembaruan dibatalkan dan dibatalkan. Jika tidak, pemicunya selesai, dan pembaruan selesai (tetapi Anda tetap harus melakukan perubahan ini).
T:Apa yang dimaksud dengan array asosiatif, dan mengapa hanya jenis koleksi ini yang digunakan, bukan koleksi lain (varray atau tabel bersarang)?
J:Koleksi PL/SQL adalah topik besar. Ikuti tautan ini untuk mempelajarinya:http:// docs.Oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005
Singkatnya - Array asosiatif (atau tabel indeks-oleh) seperti peta di java (hashmap, treemap dll) - itu adalah satu set pasangan kunci-nilai, dan setiap kunci adalah unik . Anda dapat memasukkan kunci yang sama berkali-kali ke larik ini (dengan nilai yang berbeda), tetapi kunci ini hanya akan disimpan sekali - kunci ini unik.
Saya telah menggunakannya untuk mendapatkan kumpulan departemen yang unik.
Pertimbangkan kembali contoh update kami:UPDATE treballa SET salary = salary + 10
- perintah ini menyentuh ratusan baris yang memiliki departemen yang sama. Saya tidak ingin koleksi dengan departemen yang sama diduplikasi 100 kali, saya memerlukan kumpulan departemen yang unik, dan saya ingin menjalankan kueri kami SELECT sum()...
hanya sekali untuk setiap departemen, bukan 100 kali. Dengan bantuan array sssociative, ini dilakukan secara otomatis - saya mendapatkan set departemen yang unik.