TRIGGER Trigger lar, tablo üzerinde tanımlanabilen ve bu tablo üzerinde bir işlem gerçekleştiğinde tetiklenen programlama ögeleridir. DML ve DDL trigger lar olarak ikiye ayırmak mümkündür. DML (Data Manipulation Language) => Datalar üzerinde sorgulama ve değişiklik yapmak için kullandığımız SQL deyimleridir. (SELECT,INSERT, UPDATE ve DELETE) DDL (Data Definition Language) => CREATE, ALTER ve DROP komutlarına verilen isimdir. DML Trigger ları da kendi içinde AFTER(ya da FOR) ve INSTEAD OF olmak üzere ikiye ayrılırlar. ( AFTER ve FOR birebir aynı anlamdadır. FOR anahatar sözcüğü, eski SQL sürümlerindeki alışkanlığı devam ettirmek amacı ile kullanılabilir kılınmıştır.) AFTER => Bu trigger lar tetiklendiğinde işlem gerçekleşmiş demektir. Yani yazdığımız trigger after delete şeklindeyse, o tablo üzerinde data silindikten sonra bu trigger devreye girer. INSTEAD OF => Bu trigger lar tetiklendiğinde işlem gerçekleşmemiştir. Yani yazdığımız trigger instead of delete şeklindeyse, o tablo üzerindeki kayıt silme işlemi yerine, bu trigger devreye girecektir. Trigger oluşturmak: CREATE TRIGGER trigger_adi ON tablo_adi AFTER veya INSTEAD OF (INSERT veya UPDATE veya DELETE) AS Sql ifadeler
Trigger enable/disable yapmak: disable trigger trigger_adı On tablo_adı enable trigger trigger_adı On tablo_adı Trigger silmek: drop trigger trigger_adı Trigger Ne Zaman Kullanılır? Değişiklikleri takip etmek, Birincil anahtar üretmek, Karmaşık iş kurallarını gerçekleştirmek, E-posta atmak gibi olayları otomatik olarak yapmak, Standart hata mesajlarının dışında bir hata mesajı elde etmek, Veritabanı erişimlerini takip edebilmek, Nesnede meydana gelebilecek değişiklikleri takip ve engellemektir. Trigger Ateşleyen Olaylar Trigger çalıştığı zaman iki tane sanal tablo kullanır. inserted tablosu deleted tablosu Bu tabloların içinde neler bulunur? inserted tablosunda: insert deyimi çalıştığında girilen değer update deyimi çalıştığında değiştikten sonraki veri bulunur. deleted tablosunda: delete deyimi çalıştığında silinen veri, update deyimi çalıştığında, değişmeden önceki veri bulunur. Bir kayıt güncellendiğinde ıl kayıt Deleted sahte tablosuna, değişen kayıt da Inserted sahte tablosuna yazılır.
Bir başka şekilde daha izah edelim. bir tabloya insert deyimi ile veri girildiğinde, girilen veri inserted tablosunda bulunur. Bir tablodaki veri update deyimi ile değiştirildiğinde, verinin önceki hali deleted tablosunda, yeni hali inserted tablosunda bulunur. Bir tabloda delete deyimi ile veri silindiğinde silinen veri deleted tablosunda bulunur. İnserted ve deleted tabloların yapısı ile triggerın bağlı olduğu tablonun yapısı aynıdır. Bunlar da mantıksal olarak RAM de bulunur. Trigger Türleri After Triggerler: After triggerler, kendiyle ilişkili işlem gerçekleştikten hemen sonra ateşlenir. Sadece tablolar için tanımlanabilir. Instead Of Triggerler: Belirlenen işlem gerçekleşirken devreye girer ve kendi içinde tanımlanan komutları icra etmeye başlar. Yani, belirlenen işlemin yerine geçer. After tetikleyicileri sadece tablolar için tanımlanabilirken Instead Of tetikleyicileri hem tablolar için hem de view ler için tanımlanabilirler. Örnek: create trigger InsertTrigger on products after insert print ('insert trigger tetiklendi...') test code insert into products (productname,unitprice,unitsinstock) values ('Araba',30000,1)
INSERT Trigger Bir tablo üzerinde yeni kayıtlar girildikten sonra devreye giren triggerdir. Insert trigger devreye girdikten sonra Inserted tablosunda yeni eklenen kayıtların bir kopyı tutulur. Inserted tablosu, ıl tablonun yapısal bir kopyı olup trigger sonlanana kadar saklanır. Örnek: create trigger TriggerforInsertAction on Products after insert select * from Inserted test code insert into products (productname,unitprice,unitsinstock) values ('Araba',30000,1) DELETE Trigger Tablodan bir kayıt silindiğinde otomatik olarak yapılmı istenen işlemler için DELETE triggeri kullanılır. DELETE triggeri çalıştıktan sonra silinen kayıt Deleted sahte tablosuna kaydedilir. Deleted tablosunun Inserted tablosundan farkı, ıl tablodan silinen kayıt artık Deleted tablosunda yer almaktadır. Örnek: create trigger TriggerforDeleteAction on Products after delete select * from deleted test code delete from products where productid=105
UPDATE Trigger Tablo üzerindeki kayıt ya da kayıtlarda güncelleme olduğunda devreye girecek olan triggerdir. INSERT ve DELETE triggerden biraz farklıdır. Farkı ise UPDATE trigger devreye girdiğinde Inserted sahte tablosu ıl tablodaki kayıtlardan, düzenlenmiş kayıtların kopyını, Deleted sahte tablosu ise kayıtların düzenleme işleminden önceki hallerini tutar. Örnek: create trigger TriggerforUpdateAction on products after update select * from deleted select * from inserted test code update products set unitprice=10000 where productid=104 Örnek After Trigger: sipariş verilen ürünün stok bilgisini güncelleyen trigger create trigger StokTakip on [Order Details] after insert,update,delete declare @productid int, @quantity int if exists (select * from deleted) begin select @productid=productid,@quantity=quantity from deleted update products set UnitsInStock+=@quantity where ProductID=@productId
end if exists (select * from inserted) begin select @productid=productid,@quantity=quantity from inserted update products set UnitsInStock-=@quantity where ProductID=@productId end Örnek Instead Of Trigger: create trigger AfterInsert on Products instead of insert print('instead of trigger tetiklendi..') ---test code insert into products (ProductName, UnitPrice, UnitsInStock) values ('Monitor', 250, 12) select * from Products ÖRNEK UYGULAMA: Öncelikle, Urun ve Siparis adında iki adet tablo oluşturalım. CREATE TABLE Urun ( UrunID INT PRIMARY KEY IDENTITY(1,1), UrunAd NVARCHAR(50), StokMiktar INT ) CREATE TABLE Siparis ( SiparisID INT PRIMARY KEY IDENTITY(1,1),
) UrunID INT, SiparisMiktar INT Şimdi de bu iki tablo arında ilişki olduğunu, Siparis kolonundaki UrunID nin, Urun tablosunda referans olacağını belirtelim. ALTER TABLE Siparis ADD CONSTRAINT FK_Siparis_UrunID FOREIGN KEY(UrunID) REFERENCES Urun(UrunID) Bu constraint(kısıtlama) sayesinde, Siparis tablosundaki UrunID kolonuna, Urun tablosunda kayıtlı olmayan bir ID girişi yapılamaz. Şimdi de Urun tablomuza birkaç adet ürün insert edelim. INSERT INTO Urun VALUES('Kitap',500) INSERT INTO Urun VALUES('Defter',740) INSERT INTO Urun VALUES('Silgi',220) Urun tablosundaki görüntümüz aşağıdaki gibidir. Görüldüğü gibi, Urun tablomuza 3 adet ürün girişi yaptık ve bu ürünlerin stok miktarlarını tutuyoruz. Şimdi de Siparis tablosuna insert yapalım. Ancak siparişi verirken, girmiş olduğumuz sipariş miktarı kadar, Urun tablosunda o ürün için tutulan StokMiktarının da azalmını istiyoruz. Bunun için bir trigger yazalım. Bahsettiğimiz olay, Siparis tablosuna data girişi yapıldığında tetiklenmelidir. Dolayısı ile AFTER INSERT için bir trigger yazmalıyız.
CREATE TRIGGER TRG_StokDusur ON Siparis AFTER INSERT AS DECLARE @urunid INT DECLARE @siparismiktar INT SELECT @urunid=urunid,@siparismiktar=siparismiktar FROM inserted UPDATE Urun SET StokMiktar=StokMiktar-@siparisMiktar WHERE UrunID=@urunId Artık Siparis tablosunda yapılan her insert den sonra, bu trigger devreye girecektir. Şimdi de Siparis tablosuna insert yapalım. INSERT INTO Siparis VALUES(1,100) --ID'si 1 olan Kitap adlı ürün için 100 adet sipariş verdik. Yukarıdaki kodu çalıştırdığımızda aşağıdaki mesajı alırız. Görüldüğü gibi, yapmış olduğumuz insert 2 farklı tabloyu etkilemiş durumda. Yazdığımız trigger sayesinde Urun tablosundaki StokMiktarı da update edilmiş oldu. Urun tablosundaki kayıtları tekrar görüntüleyelim. İstediğimiz sonucu elde etmiş durumdayız. İlk durumda Kitap adlı üründen 500 adet mevcuttu. Ancak 100 adet sipariş verdiğimizde, Urun tablosundaki stoktan da 100 adet düşüldüğünü ve Stok miktarının 400 olduğunu görüyoruz. Şimdi de Kitap ve Arşiv adında iki tablo oluşturalım. CREATE TABLE Kitap
( ) KitapID INT PRIMARY KEY IDENTITY(1,1), KitapAd NVARCHAR(50), Yazar NVARCHAR(50) CREATE TABLE Arsiv ( KitapID INT, KitapAd NVARCHAR(50), Yazar NVARCHAR(50), SilindigiTarih DATETIME ) Kitap tablomuza birkaç adet insert yapalım. INSERT Kitap VALUES('Melekler ve Şeytanlar','Dan Brown') INSERT Kitap VALUES('Gece Gelen Ölüm','Agatha Christie') Amacımız, Kitap tablosundan bir kayıt silindiğinde, silinen datanın o anki tarih bilgisi ile birlikte Arsiv tablosuna kaydedilmesini sağlayan bir trigger yazmak. CREATE TRIGGER TRG_ArsiveTi ON Kitap AFTER DELETE AS INSERT INTO Arsiv SELECT *,GETDATE() FROM deleted Şimdi de Kitap tablosundaki Melekler ve Şeytanlar adlı kaydı silelim. DELETE Kitap WHERE KitapID=1 Yukarıdaki örnekte olduğu gibi, yaptığımız işlemin 2 tablo üzerinde etkili olduğuna dair bir mesaj alacağız.
Arşiv tablomuzu görüntülediğimizde, sildiğimiz datanın buraya kaydedildiğini görebiliriz. Şimdi de INSTEAD OF Trigger ları ile ilgili bir örnek yapalım. Araba adında bir tablo oluşturalım. CREATE TABLE Araba ( ArabaID INT PRIMARY KEY IDENTITY(1,1), Marka NVARCHAR(20), Model NVARCHAR(20), Aktif BIT ) ALTER TABLE Araba ADD CONSTRAINT DF_Araba_Aktif DEFAULT 1 FOR Aktif Not: Aktif adlı kolonun tipi BIT olduğundan, 0 veya 1 değerlerini tutabilir. Yazdığımız constraint(kısıtlama) ile bu kolona değer girilmesse, Default olarak 1 değerini verilmesini sağladık. Oluşturduğumuz tabloya birkaç data girişi yapalım. INSERT INTO Araba(Marka,Model) VALUES('Renault','Megane') INSERT INTO Araba(Marka,Model) VALUES('Ford','Focus') INSERT INTO Araba(Marka,Model) VALUES('Audi','A3') Araba adlı tablomuzun görüntüsü aşağıdaki gibidir.
Insert ettiğimiz datalar için Aktif kolonuna değer girmememize rağmen, istediğimiz gibi default olarak 1 gelmiş durumda. Şimdi de bu tablo üzerinde yapılacak bir delete işlemi için bir trigger yazalım. Yazdığımız trigger, kaydı silmeyerek, Aktif kolonuna 0 değerini atın. Yani silme işlemi yerine update işlemi yapacağız. Dolayısı ile delete işleminin yerine başka bir iş yaptırmış olacağız. CREATE TRIGGER TRG_PifYap ON Araba INSTEAD OF DELETE AS UPDATE A SET Aktif=0 FROM Araba A JOIN deleted D ON A.ArabaID=D.ArabaID Araba tablosundan bir kayıt silelim ve tabloyu görüntüleyelim. DELETE Araba WHERE ArabaID=2 Görüldüğü gibi yapmış olduğumuz silme işlemi gerçekleşmedi. Onun yerine, yazmış olduğumuz trigger devreye girerek, silinmek istenen datanın Aktif kolonundaki değerini 0 a update etti.