Trigger_2
4 Ocak 2017 Çarşamba
Bir önceki seride After(For) trigger konusuna değinmiştik. Bu bölümde Instead Of Trigger konusuna giriş yapıyoruz. Trigger'lar her zaman olay olduktan sonra devreye giren yapılar değildirler. Instead of trigger'ları tablo değişikliğinden etkilenmeden hemen önce devreye giren yapılardır. 2 yapıyı birbirinden ayıran yegane özellik; AFTER trigger'lar sadece tablolar üzerinde tanımlanabilirken, INSTEAD OF trigger'lar hem tablolar hemde view'ler üzerinde tanımlanabilirler. Bunun dışında AFTER trigger'lar işlem yapıldıktan sonra tetiklenirken INSTEAD OF trigger'lar işlem yapılmadan önce tetiklenirler. (hatta INSTEAD OF trigger'lar, constraint'ler bile devreye girmeden önce tetiklenirler ama sözde tablolara ilgili işlem yansıtıldıktan sonra devreye girerler.)
Önemli Not: Bir tablo üstünde instead of trigger'ı tanımlanacaksa, bu tablo üstünde daha önceden CASCADE UPDATE ve CASCADE DELETE işlemleri için tanımlı constraint olmaması gerekir.
INSTEAD OF ile AFTER trigger arasındaki önemli farklar:
* Instead of trigger'lar view veya tablolar için kullanılabilir ancak After trigger'lar sadece tablolar için kullanılabilir,
* Instead of trigger'lar her view'de işlem başına sadece bir adet bulunabilir fazlası için yeni bir view tanımlayıp o view üzerinde tekrar trigger tanımlamanız gerekir ancak After trigger için her tabloda birden fazla trigger tanımlanabilir.
-------------------------------------------------------------------------
Resim-1'de belirtildiği gibi 2 adet tablom var, şimdi bunları view haline dönüştürelim:
CREATE VIEW vw_EmployeeDetails
AS
SELECT te.ID, te.Name, te.Gender, td.DeptName
FROM tblDepartment td INNER JOIN tblEmployees te ON te.DepartmentID=td.DeptID
INSERT INTO vw_EmployeeDetails VALUES(6, 'Jack', 'Male', 'HR')
Şayet ben view'e şu şekilde bir insert işlemi yapmak istersem bana aşağıdaki gibi hata verecektir.
"Msg 4405, Level 16, State 1, Line 1
View or function 'vw_EmployeeDetails' is not updatable because the modification affects multiple base tables."
View'e eklediğim satır 2 ana tabloyu etkilediği için böyle bir kayıt gerçekleştiremeyeceğini söylüyor. Yani hangi kayıt hangi tabloya gidecek SQL Server eldeki bilgileriyle buna karar veremiyor da diyebiliriz.
Bu noktada işimizi çözecek olan yapı INSTEAD OF TRIGGER'dır. vw_EmployeeDetails view'i için yazacağımız trigger aşağıdaki gibi olacaktır.
CREATE TRIGGER trg_vw_EmployeeDetails_INSTEADOFINSERT
ON vw_EmployeeDetails
INSTEAD OF INSERT
AS
BEGIN
DECLARE @DeptID INT
SELECT @DeptID=DeptID FROM tblDepartment t JOIN inserted i ON i.DeptName= t.DeptName
IF(@DeptID IS NULL)
BEGIN
RAISERROR('Invalid Department Name. Statement Terminated',16,1)
RETURN
END
INSERT INTO tblEmployees( Name, Gender, DepartmentID)
SELECT Name, Gender, @DeptID FROM inserted
END
Şimdi bu trigger'ı, olmayan bir departman üzerinden test edelim. Bakalım kod gövdesindeki gibi hata fırlatılacak mı..
INSERT INTO vw_EmployeeDetails VALUES(6, 'Jack', 'Male', 'ABCD' )
Bu sorgu ile view'e bir satır kayıt eklemek istediğimizde bize hata sonucu döndürecektir. Çünkü tblDepartment tablosunda olmayan bir kayıt 'ABCD' eklemek istiyoruz.
Sorgumuzu şu şekilde değiştirdiğimizde ilgili kaydımız sağlıklı bir şekilde çalışacaktır.
INSERT INTO vw_EmployeeDetails VALUES(6, 'Jack', 'Male', 'IT' )
Not: Bir trigger'ın INSTEAD OF trigger olup olmadığını anlamak için, OBJECTPROPERTY fonksiyonundan faydalanırız. Yukarıda oluşturduğumuz trigger üzerinden test edecek olursak yazım şekli şöyle olur:
SELECT OBJECTPROPERTY(OBJECT_ID('trg_vw_EmployeeDetails_INSTEADOFINSERT'), 'execisInsteadOfTrigger')
Şayet geriye 1 dönerse INSTEAD OF trigger, 0 dönerse AFTER trigger demektir.