Trigger oluşturma: değişiklik kaydı tutan tetikleyici yazmak
Beceri rehberi

Trigger oluşturma: değişiklik kaydı tutan tetikleyici yazmak

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 6 dk okuma

SQL Server’da CREATE TRIGGER ile bir tablodaki değişiklikleri denetim tablosuna yazan tetikleyici kurar; çok satırlı işlem ve TRUNCATE gibi tuzakları önceden görürsünüz.

Bir bakışta

  1. Tetikleyici, tablodaki değişikliğin ardından kendiliğinden çalışan koddur. SQL Server'da CREATE TRIGGER ile tanımlanır; tablo, zaman ve işlem türü belirtilir.
  2. Eski ve yeni değerler inserted ve deleted tablolarından okunur. UPDATE her ikisini de doldurur; eski değer deleted'dadır.
  3. Tetikleyici satır başına değil, komut başına çalışır. Tek satır varsayan tetikleyici toplu işlemde satır kaybeder.
  4. TRUNCATE TABLE DELETE tetikleyicisini çalıştırmaz. Silme denetimi tasarlarken yetkileri de düşünün.
  5. Tetikleyiciyi kısa, bağımsız ve belgeli tutun. Aynı iş kısıt ya da saklı yordamla çözülebiliyorsa onları tercih edin.

Trigger ne zaman gerekir, ne zaman gerekmez?

Trigger (tetikleyici), bir tabloya ya da görünüme yapılan INSERT, UPDATE veya DELETE işleminden sonra (ya da yerine) kendiliğinden çalışan, saklı yordama benzer bir koddur. Kavramın tanımı sözlük sayfasındadır; burada konu, bir tetikleyicinin SQL Server'da nasıl yazıldığı ve değişiklik kaydı gibi gerçek bir ihtiyaçta nasıl kullanıldığıdır.

Tetikleyiciyi çekici kılan, uygulama kodundan bağımsız çalışmasıdır: veriyi hangi uygulama, hangi kullanıcı ya da hangi betik değiştirirse değiştirsin kural işler. En tipik kullanımlar denetim kaydı (kim neyi ne zaman değiştirdi), tablolar arası kural denetimi (CHECK kısıtının yetmediği çapraz tablo kuralları) ve türetilmiş bilgiyi güncel tutmaktır.

Öte yandan tetikleyici görünmez bir mantıktır. Komutu yazan kişi onu çoğu zaman bilmez, hata ayıklarken beklenmedik yan etkiler çıkarır. Aynı iş bir kısıtla (PRIMARY KEY, FOREIGN KEY, CHECK, DEFAULT), bir saklı yordamla ya da uygulama katmanında çözülebiliyorsa o seçenekler genellikle daha okunur ve izlenebilirdir. Tetikleyici, kuralın hangi yoldan veri değiştirilirse değiştirilsin işlemesi gerektiğinde akla gelen araçtır.

CREATE TRIGGER: söz dizimi ve çalışma mantığı

SQL Server'da bir DML tetikleyicisi CREATE TRIGGER komutuyla tanımlanır. Komutta şu parçalar bulunur: tetikleyicinin adı, bağlı olduğu tablo ya da görünüm (ON), tetikleme zamanı (AFTER ya da INSTEAD OF) ve hangi işlemlerde çalışacağı (INSERT, UPDATE, DELETE, bunlardan biri ya da birkaçı). AS sözcüğünden sonra tetikleyicinin gövdesi gelir.

AFTER tetikleyicisi, tetikleyen komut başarıyla bittikten ve kısıtlar kontrol edildikten sonra çalışır. INSTEAD OF tetikleyicisi ise komutun yerine geçer; komutun kendi etkisi yapılmaz, siz ne yapılacağına karar verirsiniz. Microsoft belgelerine göre AFTER tetikleyicileri görünümlerde tanımlanamaz, INSTEAD OF ise tablo ve görünümlerde kullanılabilir.

Gövdede özel mantıksal tablolar kullanılır. inserted tablosu eklenen ya da güncellemeden sonraki yeni satırları, deleted tablosu silinen ya da güncellemeden önceki eski satırları taşır. UPDATE işlemi ikisini de doldurur: eski değerler deleted'da, yeni değerler inserted'dadır. Bu tablolar yalnızca tetikleyicinin içinde vardır ve tetikleyen komutun etkilediği satırları içerir.

Şekil 1

Tetikleyici, tetikleyen komutun etkilediği satırları inserted ve deleted ile görür

  1. Tetikleyen komutINSERT, UPDATE ya da DELETE tabloda satırları değiştirir.
  2. Tetikleyici çalışırinserted yeni, deleted eski değerleri taşır; AFTER tetikleyicisi komut başarılı olunca devreye girer.
  3. Sonuç kaydıGövde denetim tablosuna yazar ya da kuralı denetler; gerekirse işlemi geri alır.
Kaynak: Kaynak: Microsoft Learn CREATE TRIGGER belgesi.Mindset Institute

Örnek: stok değişikliklerini denetim tablosuna yazmak

Bir depo uygulamasında ürün stoğunun kim tarafından ne zaman değiştirildiğini kaydetmek istiyorsunuz. Önce kaydın tutulacağı tabloyu oluşturursunuz:

CREATE TABLE dbo.UrunStokLog ( log_id INT IDENTITY PRIMARY KEY, urun_id INT NOT NULL, eski_stok INT NULL, yeni_stok INT NULL, degisiklik_zamani DATETIME NOT NULL DEFAULT GETDATE(), kullanici NVARCHAR(MAX) NOT NULL DEFAULT SYSTEM_USER );

Ardından Urun tablosundaki stok sütunu değiştiğinde çalışacak tetikleyiciyi yazarsınız:

CREATE TRIGGER dbo.trg_Urun_StokDegisti ON dbo.Urun AFTER UPDATE AS BEGIN SET NOCOUNT ON; IF NOT EXISTS (SELECT * FROM inserted) RETURN; IF NOT UPDATE(stok) RETURN;

INSERT INTO dbo.UrunStokLog (urun_id, eski_stok, yeni_stok) SELECT i.urun_id, d.stok, i.stok FROM inserted AS i JOIN deleted AS d ON d.urun_id = i.urun_id WHERE i.stok <> d.stok OR (i.stok IS NULL AND d.stok IS NOT NULL) OR (i.stok IS NOT NULL AND d.stok IS NULL); END;

Satırların anlamı şöyledir. SET NOCOUNT ON, tetikleyicinin istemciye fazladan sayı mesajı göndermesini önler. Boş kümeyi erken bırakan ilk RETURN, hiçbir satır değişmediğinde gereksiz işlem yapmamayı sağlar; Microsoft belgeleri bu amaçla ROWCOUNT_BIG kontrolünü önerir. UPDATE(stok) denetimi, güncellemede stok sütununa dokunulmuşsa çalışır. Son INSERT, inserted ile deleted'ı urun_id üzerinden birleştirip yalnızca değeri gerçekten değişen satırların eski ve yeni halini kaydeder.

Denemek için birkaç ürünün stoğunu tek UPDATE ile değiştirin ve log tablosunda her ürün için ayrı bir satır oluştuğunu doğrulayın.

Çok satırlı işlemler: tetikleyici satır başına değil komut başına çalışır

SQL Server'da DML tetikleyicisi, komut bir satırı da etkilese yüzlerce satırı da etkilese, komut başına bir kez çalışır. Bu en sık yapılan hatanın kaynağıdır: tetikleyiciyi tek satır değişiyormuş gibi yazmak. Test sırasında tek satırlık güncellemelerde sorunsuz çalışan bir tetikleyici, üretimde toplu bir UPDATE geldiğinde yanlış satırı kaydeder ya da hata verir.

Tipik bir tuzak, inserted tablosundan bir değişkene değer atamaktır: SELECT @yeni = stok FROM inserted. Birden çok satır varsa değişkene yalnızca biri düşer ve kalanlar sessizce kaybolur. Çözüm, tetikleyiciyi baştan sona küme tabanlı yazmaktır: inserted ve deleted tablolarını JOIN ile birleştirip tek bir INSERT ... SELECT ya da UPDATE ... FROM ile işlemek.

Başka bir sık hata, tetikleyiciden istemciye sonuç kümesi döndürmektir. Belgelere göre tetikleyicilerden sonuç kümesi döndürme yeteneği gelecek sürümlerde kaldırılacaktır; bu tür sonuçlar sonuç beklemeyen uygulamalarda beklenmedik davranışa yol açar. Tetikleyicide sonuç döndüren SELECT yazmayın, değişken atama gerekiyorsa gövdenin başına SET NOCOUNT ON koyun.

Şekil 2

Tetikleyici tek satıra değil, komutun tüm satır kümesine göre yazılır

Sık yapılan
Doğrusu
SELECT @yeni = stok FROM inserted ile tek değer almak
inserted ve deleted'ı JOIN ile birleştirip tek komutla işlemek
Satırlar üzerinde imleç ya da döngü kurmak
Tek bir kümesel INSERT ... SELECT yazmak
Tetikleyiciden SELECT ile sonuç döndürmek
SET NOCOUNT ON kullanıp sonuç döndürmemek
Her UPDATE'te, hangi sütun değişirse değişsin çalışmak
UPDATE(sütun) denetimi ve değişen satır filtresi koymak
Kaynak: Kaynak: sayfa içeriği ve Microsoft Learn CREATE TRIGGER belgesi.Mindset Institute

AFTER mı INSTEAD OF mu? DELETE ve TRUNCATE'te ne olur?

Çoğu denetim ve kayıt işinde AFTER tetikleyicisi yeterlidir: komut başarılı olduktan sonra kaydı yazarsınız. Komutun kendisini değiştirmek ya da engellemek istiyorsanız (örneğin yalnızca belirli bir kullanıcının silmesine izin vermek, silme yerine "pasif" işaretlemek) INSTEAD OF devreye girer. Görünümler üzerinde ekleme ve güncelleme yapılabilmesi için de çoğu zaman INSTEAD OF tetikleyicisi gerekir.

Belgelerdeki bazı kısıtlar bilmeye değer: bir tablo ya da görünümde her işlem için en çok tek bir INSTEAD OF tetikleyicisi tanımlanabilir. ON DELETE ya da ON UPDATE için basamaklı (cascade) yabancı anahtarı olan tablolarda INSTEAD OF DELETE ve INSTEAD OF UPDATE tetikleyicisi tanımlanamaz.

Silme izleme konusunda önemli bir uyarı: TRUNCATE TABLE tek tek satır silmeleri kaydetmediği için DELETE tetikleyicisini çalıştırmaz. Silmeleri denetim amacıyla izliyorsanız, TRUNCATE yetkisi olan kullanıcıların tetikleyiciyi atlayabileceğini hesaba katın.

Tetikleyicinin içinde işlemi geri alabilirsiniz; belgelerdeki bir örnek, bir kural ihlalinde RAISERROR ile hata verip ROLLBACK yaparak ekleme işlemini iptal eder. Bu güçlü bir araçtır ama kullanıcıya anlamlı bir hata mesajı vermeyi ihmal etmeyin.

Riskler ve sık yapılan hatalar

Tetikleyiciler sorun çıkardığında genellikle şu nedenlerle çıkar: • Uzun süren gövde: tetikleyici, tetikleyen komutla aynı işlemin içinde çalışır ve bitene kadar kaynakları kilitli tutar. Belgeler tetikleyicileri mümkün olduğunca kısa tutmayı önerir. • Zincirleme tetiklenme: bir tetikleyici başka bir tabloyu değiştirir, o tablonun tetikleyicisi çalışır ve bu böyle sürebilir. Sonsuz döngü riski vardır; sistem iç içe çağrılara bir sınır koyar. • Sırası belli olmayan çoklu tetikleyici: aynı olay için birden çok tetikleyici varsa, ilk ve son AFTER tetikleyicisi dışında çalışma sırası tanımsızdır. Her tetikleyici kendi başına yeterli olmalıdır. • Gizli iş mantığı: kuralı yalnızca tetikleyicide tutmak, yeni geliştirici ya da veri taşıma işi için sürpriz demektir. Tetikleyicileri belgeleyin. • Veri yükleme sırasında beklenmedik yavaşlama: toplu yüklemede her komutta tetikleyici çalışır; yükleme öncesi bu durumun bilinmesi gerekir.

Bir tetikleyiciyi yayına almadan önce şu senaryoları deneyin: tek satır, çok satır, hiç satır etkilemeyen komut, hata durumunda geri alma ve toplu yükleme. Sonra mevcut tetikleyicileri bir sorgu ile listeleyip hangi tabloda hangi mantığın çalıştığını görünür kılın.

Nereden başlanır, Mindset programlarında nerede çalışılır?

Tetikleyici yazmadan önce INSERT, UPDATE, DELETE komutlarını, JOIN'i ve transaction mantığını rahat kullanıyor olmak gerekir; tetikleyici bu bilgilerin üzerine kurulur. Önce küçük bir deneme veritabanında denetim tablosu örneğini kendiniz yazmak, bu beceriyi oturtmanın en pratik yoludur.

Mindset kataloğunda SQL ile Programlama Eğitimi, Tablolarla Çalışma, Veri İşleme Dili ve Görüntüleme modül başlıklarını içerir. Tetikleyici modül başlıklarında ayrıca anılmaz; bu modüller, tetikleyicinin dayandığı tablo, satır işleme ve nesne tanımı temelini verir. Veritabanında kayıt ve kural yönetimiyle uğraşan analist, geliştirici ve operasyon ekipleri için uygun bir zemindir.

İlgili Mindset programı

SQL ile Programlama Eğitimi

Sık sorulanlar

Sık sorulan sorular

AFTER ile INSTEAD OF tetikleyicisi arasındaki fark nedir?

AFTER tetikleyicisi, tetikleyen komut başarıyla tamamlanıp kısıtlar denetlendikten sonra çalışır; genellikle kayıt tutma ve kural denetimi için kullanılır. INSTEAD OF tetikleyicisi komutun yerine geçer ve asıl işlemi yapmaz, ne yapılacağını siz yazarsınız. Görünümler üzerinde değişiklik yaparken INSTEAD OF gerekir, çünkü görünümlerde AFTER tetikleyicisi tanımlanamaz.

TRUNCATE TABLE komutu DELETE tetikleyicisini çalıştırır mı?

Hayır. Microsoft belgelerine göre TRUNCATE TABLE, tek tek satır silmelerini kayda geçirmediği için DELETE tetikleyicisini çalıştırmaz. Bu nedenle silmeleri tetikleyici ile izliyorsanız, tabloyu boşaltma yetkisine sahip kullanıcıların bu denetimi atlayabileceğini unutmayın. Yetkiyi kısıtlamak ek bir güvencedir.

Aynı olay için birden çok tetikleyici olursa hangisi önce çalışır?

SQL Server aynı olay için birden çok tetikleyiciye izin verir ama belgelere göre ilk ve son AFTER tetikleyicisi dışında çalışma sırası tanımsızdır. İlk ve son sırayı sp_settriggerorder yordamıyla belirleyebilirsiniz. Daha sağlıklı yaklaşım, her tetikleyiciyi diğerlerinden bağımsız çalışacak biçimde yazmak ve sıraya güvenmemektir.

Tetikleyici mi, saklı yordam mı kullanmalıyım?

Kural yalnızca belirli bir uygulama yolundan gelen işlemlerde işleyecekse saklı yordam daha okunur ve izlenebilirdir. Kural, verinin hangi yolla değiştirilirse değiştirilsin işlemesi gerektiğinde, yani denetim kaydı gibi durumlarda tetikleyici mantıklıdır. Tetikleyici görünmez çalıştığı için iş mantığını orada toplamaktan kaçınmak iyi bir kuraldır.

Tetikleyici içinde ROLLBACK yapılabilir mi?

Evet. Tetikleyici, tetikleyen komutla aynı işlemin içinde çalıştığı için bir kural ihlalinde ROLLBACK ile komutun tamamını geri alabilir. Belgelerdeki örnek bunu bir ekleme işleminde gösterir. ROLLBACK'ten önce kullanıcıya anlaşılır bir hata mesajı vermeniz, sorunun nedenini bulmayı kolaylaştırır.

SQL Trigger Nasıl Oluşturulur? Örnekle Anlatım