Trigger’ın türkçe karşılığı tetikleyici’dir. PL/SQL’de yazılıp saklanan yapılardır. Triggerlar yazılır ve yazılma aşamasında belirtilen koşullarda otomatik olarak çalışır. Örnek olarak tabloya bir kayıt eklediğimizde otomatik olarak kayıt tarihi olarak sistem tarihinin atması ya da tabloda bir güncelleme veya silme yaptığımızda ilgili kayıt için başka bir tabloya log kaydı atması gibi çeşitli sebepler ve kontroller için triggerlara ihtiaç duyarız.
Triggerlar aslında bir prosedürdür fakat prosedürlerden farkı Oracle tarafından çağrılmasıdır. Prosedürler bir trigger ,bir uygulama ya da kullanıcı tarafından çağrılan yapılardır. Yani trigger’lar SQL ve PL\SQL ifadelerini içerebilirler ve diğer PL\SQL birimlerini çağırabilirler, veritabanında saklanırlar, belirli durumlarda çağırılırlar.
Trigger’lar veritabanında tablolardan farklı bir yerde tutulurlar. Ayrıca triggerlar sadece tablolar üzerinde tanımlanabilirler ve tanımlandıktan sonra tabloya eklenecek veriler ile ilgilenir öncesi için bir kontrol yapmaz. View’lar üzerine tanımlanamasalarda, view’ların üzerinde bir değişiklik yapılmaya çalışıldığında view’ın üzerine tanımlandığı tablolarda kaydedilmiş trigger’lar çalıştırılır.
Trigger’ın Tetiklendiği Durum Tipleri ;
- Herhangi bir DML ifadesi : INSERT, UPDATE, DELETE
- Herhangi bir DDLifadesi: CREATE, ALTER, DROP
- Herhagi bir veritabanı işleminde: Örnek olarak Logon, Logoff, Startup, Shutdown işleminde.
Trigger’in Faydaları ;
- Sütunlar için otomatik olarak değerler üretmesi
- Güvenlik katmanı oluşturmak için
- Loglama
- Yapılan işlemlerle ilgili kayıt oluşturmak için
- Tablolar arasında eşleme ve eşitleme yapmak için
- Tablo erişimiyle ilgili bilgiler toplamak için
- Uygun olmayan transaction’ları engellemek için
Trigger Oluşturma
Trigger üç kısımdan oluşmakta.
- İlk kısım triggerın hangi tablo üzerinde ne zaman çalışacağını gösteriyor
- İkinci kısım WHEN ile aşağıda belirttiğimiz koşul kısmı ki triggerın ne zaman tetikleneceği bu kısma bağlıdır.
- Üçüncü kısım ise Declare-Begin-Exception-End bloğu ile belirttiğimiz aksiyon kısmıdır yani bu triggerın ne iş yapacağını belirttiğimiz kısımdır.
CREATE [OR REPLACE ] TRIGGER trigger_name {BEFORE | AFTER | INSTEAD OF } {INSERT [OR] | UPDATE [OR] | DELETE} [OF col_name] ON table_name [REFERENCING OLD AS o NEW AS n] [FOR EACH ROW] WHEN (condition) DECLARE Declaration-statements BEGIN Executable-statements EXCEPTION Exception-handling-statements END;
- CREATE [OR REPLACE] TRIGGER trigger_name: Belirttigimiz isimde yeniden oluşturur veya varolan trigger la değiştirir.
- {BEFORE | AFTER | INSTEAD OF} : Trigger’in ne zaman tetikleneceğini belirleriz.Önce mi,sonra mı veya yerine mi.
- {INSERT [OR] | UPDATE [OR] | DELETE}: Hangi DML işlemi için trigger olması gerektiğini belirtiriz.
- [OF col_name]: Hangi sütun için trigger olması gerektiğini belirtiriz.
- [ON table_name]: Hangi tablo için trigger olması gerektiğini belirtiriz.
- [REFERENCING OLD AS o NEW AS n]: DML sorgularındaki eski ve yeni değerleri verir.
DML İfadesi | OLD | NEW |
INSERT | Null | Insert edilen değer |
UPDATE | Update öncesindeki değer | Update sonrasındaki değer |
DELETE | Silinmeden önceki değer | null |
- [FOR EACH ROW]: Etkilenen her satır için çalışmasını sağlar.
- WHEN (condition): FOR EACH ROW kullandığımızda kullanabiliriz.Etkilenen satırları kısıtlamak için kullanabiliriz.
NOT : Trigger içerisinde çalışma sırası aşağıdaki gibidir.
- Önce “Before” triggerı varsa çalışır.
- Ardından “Before Row” triggerı kullanılır.
- Trigger içerisindeki Begin – End bloğundaki işlemler yapılır
- “After Row” trigger’ı bulunuyorsa o çalıştırılır.
- “After” triggerı tetiklenir.
Örnek 1;
--Yeni bir trigger olustururuz veya varolani ezeriz CREATE OR REPLACE TRIGGER display_salary_changes --customers tablosuna INSERT,UPDATE,DELETE ifadeleri calistirilmadan once BEFORE DELETE OR INSERT OR UPDATE ON customers --Yukaridaki sartlardan etkilenen her satir icin FOR EACH ROW --id'si 0'dan buyuk olan WHEN (NEW.ID > 0) DECLARE sal_diff number; BEGIN sal_diff := :NEW.salary - :OLD.salary; dbms_output.put_line('Old salary: ' || :OLD.salary); dbms_output.put_line('New salary: ' || :NEW.salary); dbms_output.put_line('Salary difference: ' || sal_diff); END; /
NOT : Trigger içerisinde yukarıdaki gibi insert,update ve delete işlemini de katarak bir yapı oluşturduğunuz da hepsi için tek bir aksiyon tanımlamanıza gerek yoktur. Aşağıdaki gibi her bir DML işlemi için ayrı ayrı aksiyonlar tanımlayabilirsiniz.
- IF INSERTING THEN…
- IF DELETING THEN…
- IF UPDATING(kolon_ismi) THEN…
CREATE OR REPLACE TRIGGER log_customers BEFORE DELETE OR INSERT OR UPDATE ON customers FOR EACH ROW DECLARE v_ChangeType CHAR (1); BEGIN IF INSERTING THEN v_ChangeType := 'I'; ELSIF UPDATING THEN v_ChangeType := 'U'; ELSE v_ChangeType := 'D'; END IF; DBMS_OUTPUT.put_line (v_ChangeType || ' ' || USER || ' ' || SYSDATE); END; /
Örnek;
CREATE OR REPLACE TRIGGER trig_exam_1 BEFORE UPDATE ON customers FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO mustafa.customers_log (ID,NAME,AGE,ADDRESS,SALARY,UPDATE_DATE) VALUES (:OLD.ID,:OLD.NAME,:OLD.AGE,:OLD.ADDRESS,:OLD.SALARY,SYSDATE); INSERT INTO mustafa.customers_log (ID,NAME,AGE,ADDRESS,SALARY,UPDATE_DATE) VALUES (:NEW.ID,:NEW.NAME,:NEW.AGE,:NEW.ADDRESS,:NEW.SALARY,SYSDATE); COMMIT; END; /
NOT : ‘ORA-04092: cannot COMMIT in a trigger’ böyle bir hata alınıyorsa. AUTONOMOUS_TRANSACTION kullanmamız gerekir.
Autonomous transactionlar başka bir transaction tarafindan başlatılan ve kendisini çağıran(başlatan) transactiondan (main transaction) tamamen bağımsız çalışan transactionlardır. Örneğin bir transaction içerisinde işlemin sonucuna bakılmaksızın log oluşturmak istiyor olalım, log tablomuz işlem başarılıysa zaman,kullanıcı gibi bilgileri, başarısız olursa zaman ve kullanıcı ile beraber alınan hata bilgisini tutuyor olsun. Transaction içerisinde işlem başarılıysa commit edeceğimiz için sorun yok log tablomuza da insert yapıp commit ile kaydederiz. Peki transaction içersinde hata aldık ve rollback yapmak istersek ne olacak? İşte burada ana transactionumuzdan bağımsız çalışan ve log tablomuza her şartta kayıt yazan bir alt programa ihtiyacımız olacak ve bu transaction ana transaction sonucu ne olursa olsun log tablomuza yazdığı kaydı commit edecek.
Örnek ;
CREATE OR REPLACE TRIGGER trig_exam_2 BEFORE DELETE ON customers FOR EACH ROW DECLARE BEGIN raise_application_error (-20000,'SILME_YOK : Bu tablodan kayit silemezsiniz...'); END; /
Örnek ;
CREATE OR REPLACE TRIGGER trig_exam_3 AFTER LOGON ON DATABASE BEGIN IF SYS_CONTEXT('USERENV','SESSION_USER') IN ('AAAAAAAA') THEN raise_application_error(-20003,'Veritabanına bağlantınız engellendi,lütfen sistem yöneticinizle görüşün..'); END IF; END; /
Örnek ;
CREATE OR REPLACE PROCEDURE trig_exam_4_proce (ddlsql VARCHAR2) AS l_sql VARCHAR2 (100); BEGIN l_sql :='insert into ddl_trigger_logs values(sysdate, ''<' || ddlsql || '<'')'; EXECUTE IMMEDIATE l_sql; l_sql := 'grant select on mustafa.' || ddlsql || ' to deneme'; EXECUTE IMMEDIATE l_sql; COMMIT; END; CREATE OR REPLACE TRIGGER trig_exam_4 AFTER CREATE ON mustafa.customers DECLARE job_number NUMBER; BEGIN DBMS_JOB.SUBMIT (job_number,'trig_exam_4_proce(''' || ora_dict_obj_name || ''');',SYSDATE + 5 / 24 / 60 / 60); END;
NOT : Triggeri bir süreliğine disable veya enable edebiliriz. Veya bir tabloya ait bütün triggerlerı disable,enable edebiliriz.
ALTER TRIGGER trigger_name DISABLE; ALTER TABLE table_name DISABLE ALL TRIGGERS; ALTER TRIGGER trigger_name ENABLE; ALTER TABLE table_name ENABLE ALL TRIGGERS;
NOT : Triggeri aşağıdaki sintaksisi kullanarak silebiliriz.
DROP TRIGGER trigger_name;
NOT : Trigger lar ile ilgili view ler aşağıdaki gibidir.
- trigger$
- dba_source
- DBA_TRIGGERS
- ALL_TRIGGERS
- USER_TRIGGERS
- DBA_TRIGGER_COLS
- ALL_TRIGGER_COLS
- USER_TRIGGER_COLS
- DBA_TRIGGER_ORDERING
- ALL_TRIGGER_ORDERING
- USER_TRIGGER_ORDERING
- DBA_INTERNAL_TRIGGERS
- ALL_INTERNAL_TRIGGERS
- USER_INTERNAL_TRIGGERS
- LOADER_TRIGGER_INFO
Yararlı olması Dilegiyle …
Yazar : Mustafa Bektaş Tepe
Kaynaklar;
http://www.tutorialspoint.com/plsql/plsql_basic_syntax.htm
https://developersdaily.wordpress.com
http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/
https://docs.oracle.com/cd/E11882_01/appdev.112/e40758/toc.htm
https://oracle-base.com/articles/misc/introduction-to-plsql