MsSQL

Sql Server’da Trigger Kullanımı

Trigger Türkçe anlamı olarak Tetikleyici demektir.  Trigger, Stored Procedureler gibi  Sql Server içinde bileşen olarak bulunmaktadır.  Triggerların kullanım amacı, tablo üzerinde bir işlem gerçekleştiğinde (insert, update, delete) başka bir işlem daha yapılmak istendiği zaman kullanılır.

Şu şekilde basit olarak örneklendirelim.

Öğrenci tablonuz olduğunu düşünelim. Öğrenci tablonuzda bir öğrenciyi sildiğinizde bu öğrenci bilgilerini daha farklı bir tabloda(silinen öğrencilerin tutulduğu) tutmak istiyorsunuz. Öğrenci tablosundaki bir kayıt silindiğinde(delete) başka bir tabloya bu kaydı trigger ile aktarmak mümkün.

Yada daha kapsamlı başka bir örnek  Bir kütüphane tablosu üzeride, bir öğrenci sadece bir kitap alabilir durumda olsun. Öğrenci kitabı getirmediği sürece ikinci bir kitap almasına izin verilmesin. Bu işlemi görsel program aracılığı ile yapabileceğiniz gibi trigger ile öğrenci kitap teslim etmediyse ikinci bir kitabı almasına izin verilmesini engelleyebilirsiniz. Yazının sonunda çok daha fazla senaryo ile örneklendirme yapacağım.

Trigger’lar DML (Delete, Insert ve Update işlemleri) işlemleri üzerinde çalışırlar. Select ile bir bağlantısı yoktur.  DML işlemi gerçekleştiğinde deleted, inserted yada her iki sanal tablolaya kayıtlar eklenir. Trigger tetiklenerek, trigger içindeki sorgular gerçekleştirilir. Sonra da kayıtlar gerçek tabloya(rollback ile sorguyu iptal edebiliriz)  eklenerek sorgu işlemi bitirilir.

Adım adım trigger oluşturma kavramına bir bakalım.

Trigger Oluşturma

CREATE TRIGGER trigger_adi
ON tablo_adi
{FOR|AFTER|INSTEAD OF} {INSERT|UPDATE|DELETE}
AS
Begin
--Sql ifadeler
End

trigger_adi: oluşturacağımız trigger adını veriyoruz.

tablo_adi: hangi tabloda çalışacağını belirtiyoruz

After yada Instead of: after yapılırsa işlem yapıldıktan sonra, instead of yapıldığında yapmak istediğimiz işlemin yerine çalıştırılacağını belirtiyoruz

Insert,Update, Delete: Tabloda hangi sql işlemi sırasında çalıştırılacağını belirtiyoruz.

Begin…..End: Trigger çalıştırıldıktan sonra yürütülecek olan sql cümlelerini bu aralıkta yazıyoruz.

 

Trigger Güncelleme 

ALTER TRIGGER trigger_adi
ON tablo_adi
AFTER veya INSTEAD OF (INSERT , UPDATE , DELETE)
AS
Begin
--Sql ifadeler
End

 

Inserted / Deleted Kavramları

Trigger’ın çalışmasına göre, hangi tablo üzerinde etkinse tablo üzerine eklenilen veya güncellenilen kayıtları “inserted” üzerinde, silinen kayıtları ise “deleted” üzerinde kaydediyor. Bunlar sanal tablolardır (virtual table).
Insert: Bir insert işlemi gerçekleştirdiğimizde, eklediğimiz kayıt ilk olarak inserted tablosuna eklenir.

Delete:Bir delete işlemi gerçekleştirdiğimizde sildiğimiz kayıt ilk olarak deleted tablosuna eklenir.

Update:Update işleminde ise eski kayıt önce deleted tablosuna, güncellenen(yeni) kayıt ise inserted tablosuna eklenir.

 

Trigger enable/disable yapma

Enable (Aktifleştirme):

--yöntem 1
disable trigger trigger_adı On tablo_adı

--yöntem 2
alter table tablo_adı disable trigger trigger_adı

Disable (Pasifleştirme):

--Yöntem 1
enable trigger trigger_adı On tablo_adı

--Yöntem 2
alter table tablo_adı enable trigger trigger_adı

 

Tüm Triggerları Pasifleştirme / Aktifleştirme

enable trigger all On tablo_adı

disable trigger all On tablo_adı

 

Trigger Kaldırma

Kaldırma :

drop trigger trigger_adı

 

After /Instead Of Kavramı

After Triggerler: Insert,Update yada Delete işlemi gerçekleştirildiğinde tetiklenir. Sadece tablolar için tanımlanabilir.

Instead Of Triggerler: Belirlenen işlem gerçekleşirken devreye girip, SQL sorgusu yerine çalıştırılır.  After tetikleyicileri sadece tablolar için tanımlanabilirken Instead Of tetikleyicileri hem tablolar için hem de view tabloları ile de kullanılabilir.

 

Rollback  Transaction ve Raise Error

Rollback Transaction komutu trigger ne için tanımlanmışsa o işlemi iptal etmek için kullanılır.

Raise Error komutu kullanıcıya işlemin neden iptal edildiğini bildirmek için kullanılır. Kullanıcıyı bilgilendirme amacı ile kullanılır.

 

Sql Server Management Trigger Nerede Bulunur

Sql Server Management  üzerinde triggerlar aşağıdaki resimde görüntülendiği gibi ilgili tabloya tıklandığında tablonun altında görünecektir.

 

Aşağıdaki Komutlar Trigger İçine Kullanılmaz

Alter Database          Create Database

Load Database          Drop Database

Disk Init                     Disk Resize

Load Log                   Reconfigure

Restore Database    Restore Log

 

Recursive Trigger Oluşturma

Trigger’ın kendini çağırması durumudur.

Triggerda aynı tabloda işlem yapılıyorsa o işlem sonucu aynı trigger bir daha çalışabilir.

Trigger başka tabloda işlem yapar. O işlem sonucu çalışan başka bir triggerda yeniden birinci tablo ile ilgili işlem yapar. Bu durum da da recursive olur.

32 tane en fazla çalışır.

Sürekli bir şart ile kontrol edilip sonlandırılmalıdır. Yoksa sonsuz döngüye girer.

 

Alter database ticaret set recursive_triggers on

sp_dpoption ticaret,'recursive triggers',true

 

Recursive trigger’ları aktif yapmak için yukarıdaki kodlar kullanılır.

Bir alanının güncellendiğini öğrenmek için update(alanadi) fonksiyonu kullanılır. Sonucu true yada false olarak döner.

Bir trigger başka bir tabloda işlem yaparken o tablodaki trigger’ı da çalıştırabilir.

İç içe 32 trigger çalıştırılabilir.

@@Nestlevel hangi seviyede olduğunu belirtir.

Sp_configure procedure’ü kullanılarak iç içe tetiklenme kapatılabilir.

İlk trigger çalışır diğerleri tetiklenmez.

 

Trigger Örnekleri

Trigger örneklerini basit olarak oluşturulmuş kütüphane veritabanı üzerinde uygulayacağım. Kütüphane veritabanını indirmek için tıklayın.

Aşağıdaki örneklerde triggerlar bir kez execute ile yürütüldükten sonra insert/update/delete işlemleri gerçekleştirildiğinde ilgili trigger tetiklenecektir.

Bazı örneklerde triggerlar bir birlerini etkileyeceği için ya triggerı kaldırmanız yada bir birini etkileyeceğini düşündüğünüz triggerları durdurmanız gerekir.



 

Örnek: Kullanıcı bir kayıt ekledikten sonra ogrenci tablosunu listeleyen trigger oluşturunuz.

--trigger kodu
create trigger trg_Listele on ogrenci
after insert
as
begin
select * from ogrenci
end


--Kayıt ekleme örneği
insert into ogrenci(ograd,ogrsoyad,cinsiyet,dtarih,sinif,puan)values('Ali','Veli','E',GETDATE(),'10A',0) --ÖNCE TRİGGER I ÇALIŞTIR

 

Örnek: 10A sınıfına cinsiyeti kız olan öğrenciler kaydedilebilsin

Create trigger cinsiyet on ogrenci
for insert
As
if(exists(Select * from inserted where sinif = '10A' and cinsiyet = 'E'))
Begin
  raiserror('10A sınıfına erkek öğrenci kaydedilemez',1,1)
  rollback transaction
End


--Kayıt ekleme test
insert into ogrenci(ograd,ogrsoyad,cinsiyet,dtarih,sinif,puan)values('Ali','Veli','E',GETDATE(),'10A',0) --ÖNCE TRİGGER I ÇALIŞTIR

 

Örnek: 10A’nın kız öğrencileri silinemesin

Create trigger trg_10AKizOgrenciSilme on ogrenci
after delete
as
begin
   if(exists(select * from deleted where cinsiyet='K' and sinif='10A'))
    begin
     raiserror('10A sınıfındaki kız öğrencileri silemezsiniz!!',0,0)
     rollback transaction
    end
end

delete from ogrenci where cinsiyet='K' and sinif='10A' --kullanadan önce triggerı çalıştırmayı unutmayın

 

Örnek: Silinen öğrenciler başka bir tabloya kaydedilsin

--silinen öğrencinin adını soyadını mezun tablosuna kaydediyoruz.
create table mezun(ograd varchar(50),ogrsoyad varchar(50))

create trigger trg_SilineniEkle on ogrenci
after delete
as begin
insert into mezun select ograd,ogrsoyad from deleted
end


delete from ogrenci where ogrno=3 --triggerı test ediyoruz
select * from mezun

 

Örnek: Öğrencilerin cinsiyet alanı güncellenmesin

create trigger trg_Guncelle on ogrenci
after update
as begin
--if(update(cinsiyet))
if(exists(select * from inserted,deleted where inserted.ogrno=deleted.ogrno and inserted.cinsiyet!=deleted.cinsiyet)) 
--Exists içindeki değerin olup olmadığına bakar.
begin
raiserror('Cinsiyet Güncellenemez.',1,1)
rollback transaction
end
end

--trigger test edilmesi
select * from ogrenci where ogrno = 5
update ogrenci set cinsiyet = 'E' where ogrno=5

 

Örnek: Kitap tablosu güncellenirken eski sayfa sayısı yeni sayfa sayısından fazla olmak zorunda

create trigger kitapguncelle on kitap
after update
as
begin
if(exists(select * from inserted,deleted where inserted.sayfasayisi=deleted.sayfasayisi or  inserted.sayfasayisi > deleted.sayfasayisi))
begin
raiserror('Eski sayfa sayısı yeni sayfa sayısından fazla olmak zorunda',1,1)
rollback transaction
end
end

--Birinci Kontrol
update kitap set puan=20, sayfasayisi=150 where kitapno=1
select * from kitap where kitapno=1


--İkinci Kontrol
update kitap set puan=20, sayfasayisi=170 where kitapno=1
select * from kitap where kitapno=1

 

Örnek: Tür tablosundan hiçbir kayıt silinmesin

Create Trigger trg_TurSilinmez on tur
after delete
as
begin
raiserror('tur Tablosu üzerinde kayıt silinmez',1,1)
rollback transaction
end


delete from tur

select * from tur

After yerine Instead of kullanılarak delete işlemi yapmak yerine hata vermesi sağlanabilir.

Create Trigger trg_TurSilinmez on tur
instead of delete
as
begin
raiserror('tur Tablosu üzerinde kayıt silinmez',1,1)
rollback transaction
end





Örnek:  Ogrenci tablosuna silindi isminde bir alan ekleyiniz. Ogrenci silinmesin silindi alanının değeri 1 olsun –instead of kullanılacak after yerine

Alter Table ogrenci add silindi bit null

Create trigger ogrenciSil on ogrenci
instead of delete
as
begin
update ogrenci set silindi=1 where ogrno in (select ogrno from deleted)
end



--triggerı çalıştırmayı unutmayın. daha önce oluşturulan triggerlar ile çakışmaması için eskilerini durdurmayı unutmayın
delete from ogrenci where ogrno in(8,9)
select * from ogrenci where ogrno in (8,9)

 

Örnek: Tur tablosuna gTarih adında bi alan ekleyin tur tablosunda guncelleme yapıldığında gtarih alanına güncelleme tarihini kaydediniz.

Alter Table tur add gTarih datetime null

Create Trigger turGuncelle on tur
after update
as
begin
--if(not update(guncellendi))--recursive trigger açıksa hata verememesi için
  update tur set gTarih=GETDATE() where turno in (select turno from deleted)
end

update tur set turadi='Başka Bir Tür'where turno=3
select * from tur where turno=3

Örnek: 500 sayfadan daha az roman türünde kitap eklenemesin

Create trigger kitap1 on kitap
after insert
as
if(exists(Select * from inserted,tur where inserted.turno = tur.turno and
turadi='roman' and sayfasayisi<500))
begin
  raiserror('500 sayfadan az roman türünde kitap kaydedilemez',1,1);
  rollback transaction
End

 

Yorum

  • Ben C#la hazırladığım programın database ni sql serverle bağladım şimdi c# da bisiklet kiralama ve teslim işlemi yaptığım formum var kiralama ekranımda KiraId KiralayanKisiId KiralanaBisikletId KiralananIstasyonId
    TeslimTarihi TeslimSaati TeslimAlınaGorevliId bölümleri mevcut teslim formumda da KiraId TeslimTarihi TeslimSaati IadeTarihi IadeSaati IadeEdilenGorevliId KiralamaSüresi KiraUcreti ve bu 2 form aynı tablo üzerinde işlem yapıyor ve benim sorum da TeslimAlınaGorevliId ile IadeEdilenGorevliId aynı değil ise bisikletin zimmetli oldugu istasyon değişicek
    zimmet tablom görevli tablom bisiklet tablom İstasyon tablom da var bunlarda bir birleriyle ilişkili bu sorumu triggerla yazmak istiyorum ama bunun için tanımladıgım değişkenlere sorgularla atamalar yapıp koşulu ssağlarsa zimmet ekranında güncelleme gerçekleşecek bunla ilgili fikirleri niz nedir

  • Disable devre dısı bırakmak demektir, dolayısıyla triggeri pasiflestirirken Enable degıl Disable kullanırız, tam tersidir.

  • hocam “raiserror” da ifadeden sonra girdğimiz sayılar neye göre değişiyor.

    “raiserror(‘tur Tablosu üzerinde kayıt silinmez’,1,1)” mesela burada neden 1,1 de 0,0 değil ?

    • Hata mesajları konusu sql serverda uzun bir konu. Ama yinde özet olması bakımından birşeyler yazayım. Sql Server üzerinde hata mesajları üç parça halinde belirtilmektedir. Msg,level ve state olarak ifade ediliyor. Msg kodu hatanın sql server tarafından belirtilen kod numarasıdır. msg:50000 Kullanıcı tanımlı hataları ifade etmek için kullanılır. Level ise hatanın seviyesini belirtmek için kullanılıyor. Yanılmıyorsam 25’e kadar değer alabiliyordu. Son olarak da hata ile ilgili durum(state) belirtmek için de state değeri veriliyor. Bir hata grubu içinde farklı durumlar olabilir. Bunları gruplandırmak için kullanılıyor. Şuana kadar kullanmadım ama bir ara inceleyip konu ile ilgili yazı yazmak isterim.
      Özetle 1den fazla hata verdireceksen her hata için 1,1 yerine seviye ve durum değerlerini değiştirerek program tarafında hatayı numarası ile belirtme şansına sahip olursun.

  • “Örnek: Kitap tablosu güncellenirken eski sayfa sayısı yeni sayfa sayısından fazla olmak zorunda.”
    Hocam bu soruda
    inserted.sayfasayisi=deleted.sayfasayisi AND inserted.sayfasayisi > deleted.sayfasayisi))

    AND yerine OR olması gerekmiyor mu?

    Kolay gelsin iyi çalışmalar

Yorum Yap