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.

  1. Önce “Before” triggerı varsa çalışır.
  2. Ardından “Before Row” triggerı kullanılır.
  3. Trigger içerisindeki Begin – End bloğundaki işlemler yapılır
  4. “After Row” trigger’ı bulunuyorsa o çalıştırılır.
  5. “After” triggerı tetiklenir.

Örnek 1;

PL/SQL TRIGGERS - PL/SQL TRIGGER - PL/SQL Tetikleyici

--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;
/

PL-SQL TRIGGERS

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

Loading