21 Nisan 2011 Perşembe

SQL Trigger Kavramı

Trigger’lar, tablo üzerinde tanımlanabilen ve bu tablo üzerinde bir işlem gerçekleştiğinde tetiklenen programlama ögeleridir. Çalışma yapısı, C#’daki event mantığı ile aynıdır.

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.

Bu yazımızda DML Trigger’lar üzerinde inceleme yapacağız. Insert, Update ve Delete işlemleri için arka planda oluşan ‘insterted’ ve ‘deleted’ tablolarını kullanacağız. Bu tablolar hakkında daha detaylı bilgiye şuradan erişebilirsiniz.

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.

Tanımlarken biraz karmaşık gelse de örnekler üzerinde daha iyi anlaşılacağını düşünüyorum. İlk olarak AFTER Trigger’ı ile ilgili inceleme yapalım.

Örneğimize başlamadan önce, 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 arası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.

Untitled

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 azalması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 mesajlı alırız.

Untitled2

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.

Untitled3

İstediğimiz sonucu elde etmiş durumdayız. İik 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_ArsiveTasi

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.

Untitled2

Arşiv tablomuzu görüntülediğimizde, sildiğimiz datanın buraya kaydedildiğini görebiliriz.

Untitled4

Ş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.

Untitled5

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 atası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_PasifYap

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

Untitled6

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.

Faydalı olması dileği ile…



25 yorum:

Adsız dedi ki...

yazını için çook teşekür ederim web tasarımcı olarak çook işme yarayacak bir olay :D

Onur Salkaya dedi ki...

Yorumunuz için ben teşekkür ederim, işinize yaramasına sevindim. İyi çalışmalar..

Adsız dedi ki...

Bir matematik mühendisi olarak seni tebrik ederim Onur yazdıkların çok başarılı :)
Gamze

Onur Salkaya dedi ki...

Çok teşekkür ederim Gamze, faydalı olması dileği ile...

Adsız dedi ki...

süper olmuş, merak eder dururdum nedir bu trigger diye sayende çok iyi anladım. öğretmen olmalısın sen.. tebrikler. ferit

Adsız dedi ki...

Çok faydalı bir makale olmuş tebrik ederim. Elinize sağlık. Başarılarınızın devamını dilerim.

Adsız dedi ki...

eline salık emeğine sağlık

Adsız dedi ki...

triggerla oluşturduğum bir tabloya aynı trigger içinde nasıl trigger ekleyebilirim?

Şehmus GÖKALP dedi ki...

RSS listeme eklendin .Tebrikler

Unknown dedi ki...

Teşekkürler

Adsız dedi ki...

çok yararlı bilgi...eline sağlık

Adsız dedi ki...

çok teşekkürler.. ellerinize sağlık..

Unknown dedi ki...

faydalı paylaşım için teşekkür ederim.

Adsız dedi ki...

Adamsın..

Adsız dedi ki...

Teşekkürler çık faydalı bir yazı olmuş.

Adsız dedi ki...

gayet anlaşır bir yazı olmuş, elinize sağlık

Adsız dedi ki...

Süper bir anlatım olmuş süper.

Unknown dedi ki...

Çok İyi Ama Eksik diye düşünüyorum neyse beğendim!

Adsız dedi ki...

Teşekkür ederim Onur.

Burak Doğan dedi ki...

Çok teşekkürler. Harika bir anlatım olmuş.

onursalkaya dedi ki...

nice job. thanks dude.

Adsız dedi ki...

hocam bu from dan sonraki INSERTED ve DELETED dememizin mantığı ne

ONUR TURKDAMAR dedi ki...

Anlatım cok iyi gercekten teşekkürler harika

Adsız dedi ki...

Üstad eline sağlık,update için de bir örnek verir misin ?
iki aynı tablo ve veriler,birinde bir veri değişince diğerinde de aynı verinin değişmesi için nasıl bir yol izlemeliyiz ?

Onur Salkaya dedi ki...

Merhaba,

Öncelikle teşekkür ederim. İlgili örneğe aşağıdaki linkten ulaşabilirsiniz.

http://onursalkaya.blogspot.com.tr/2011/12/sql-trigger-kavram-ii.html

Yorum Gönder