SQL Server 2005 Ekleme Tetikleyici Sorununu Anlamak

SQL Server 2005 ile çalışırken, tetikleyicinizin bir hedef tabloya yalnızca bir kayıt eklediği bir durumla karşılaşabilirsiniz; oysa ana ekleme işleminiz birden fazla kayıt oluşturur. Bu, özellikle bir alt sorgu kullanarak ana tablonuza veri eklerken oldukça sinir bozucu olabilir. Bu yazıda, yaygın bir sorunu ve onun potansiyel çözümünü detaylı bir şekilde ele alacağız.

Sorunun Açıklaması

Bir tblMenuItems adlı tablonuz olduğunu hayal edin ve buna yeni kayıtlar eklediğinizde, tblMenuItemInsertSecurity tetikleyicinizin otomatik olarak başka bir tabloya (tblRestrictedMenuItems) kayıt eklemesini istiyorsunuz. Tetikleyici, tek bir kayıt eklendiğinde gayet iyi çalışıyor gibi görünüyor; ancak, bir alt sorgu birden fazla kayıt getirdiğinde beklenildiği gibi davranmıyor.

İşte Ekleme İfadesi

INSERT INTO [tblMenuItems] ([ID], [MenuID], [SortOrder], [ItemReference], [MenuReference], [ConcurrencyID]) 
SELECT [ID], [MenuID], [SortOrder], [ItemReference], [MenuReference], [ConcurrencyID] 
FROM [IVEEtblMenuItems]

Tetikleyici Kod Parçası

CREATE TRIGGER [dbo].[tblMenuItemInsertSecurity] ON [dbo].[tblMenuItems] 
FOR INSERT
AS
BEGIN
    DECLARE @iRoleID int
    DECLARE @iMenuItemID int

    SELECT @iMenuItemID = [ID] FROM Inserted

    DECLARE tblUserRoles CURSOR FASTFORWARD FOR SELECT [ID] FROM tblUserRoles
    OPEN tblUserRoles 
    FETCH NEXT FROM tblUserRoles INTO @iRoleID 

    WHILE (@@FetchStatus = 0)
    BEGIN
        INSERT INTO tblRestrictedMenuItems (
            [RoleID],
            [MenuItemID],
            [RestrictLevel])
        VALUES (
            @iRoleID,
            @iMenuItemID,
            1)    

        FETCH NEXT FROM tblUserRoles INTO @iRoleID 
    END

    CLOSE tblUserRoles 
    DEALLOCATE tblUserRoles
END

Tetikleyicinin Neden Başarısız Olduğunu Anlamak

Tetikleyicinizin çoklu kayıt eklememesinin temel nedeni, Inserted sahte tablo kullanımına bağlıdır. Tetikleyici çalıştığında, Inserted tablosu eklenen tüm satırları içerir, ancak tetikleyici mantığınız yalnızca ilk satırı yanlış bir şekilde işler.

Anlaşılması Gereken Temel Kavramlar

  • Tetikleyiciler ve Satırlar: SQL Server’da bir tetikleyici, her tetikleme işlemi (ekleme, güncelleme, silme) için bir kez tetiklenir ve birden fazla satır üzerinde aynı anda işlem yapabilir.

  • Inserted Sahte Tablosu: Bu tablo, eklenen kayıtlara erişim sağlar ve yalnızca ilki değil, tüm satırları içerir.

Çözüm: Tetikleyici Mantığını Ayarlamak

Birden fazla kayıt için eklemeleri etkili bir şekilde işlemek için tetikleyicinizi iki şekilde yeniden yapılandırabilirsiniz: bir döngüyle bir imlec kullanarak (detaylandıracağız) veya set tabanlı işlemleri kullanarak, bu daha verimlidir.

1. Bir İmlec ile Yeniden Yapılandırma

Inserted sahte tablosu üzerinden bir imlec kullanarak döngü yapabilirsiniz, ancak bu yaklaşım büyük veri kümesiyle performans sorunlarına yol açabilir.

İşte bir imlec kullanarak tetikleyicinizin gözden geçirilmiş bir versiyonu:

CREATE TRIGGER [dbo].[tblMenuItemInsertSecurity] ON [dbo].[tblMenuItems] 
FOR INSERT
AS
BEGIN
    DECLARE @iRoleID int
    DECLARE @iMenuItemID int

    DECLARE tblUserRoles CURSOR FASTFORWARD FOR SELECT [ID] FROM tblUserRoles
    OPEN tblUserRoles 
    FETCH NEXT FROM tblUserRoles INTO @iRoleID 

    -- Inserted tablosundaki her satır için döngü
    DECLARE tblInserted CURSOR FOR SELECT [ID] FROM Inserted
    OPEN tblInserted 
    FETCH NEXT FROM tblInserted INTO @iMenuItemID 

    WHILE @@FETCH_STATUS = 0
    BEGIN
        WHILE (@@FetchStatus = 0)
        BEGIN
            INSERT INTO tblRestrictedMenuItems (
                [RoleID],
                [MenuItemID],
                [RestrictLevel])
            VALUES (
                @iRoleID,
                @iMenuItemID,
                1)    

            FETCH NEXT FROM tblUserRoles INTO @iRoleID 
        END

        FETCH NEXT FROM tblInserted INTO @iMenuItemID 
    END

    CLOSE tblInserted
    DEALLOCATE tblInserted
    CLOSE tblUserRoles 
    DEALLOCATE tblUserRoles
END

2. Set-Bazlı İşlemler Kullanmak (Tavsiye Edilir)

Bu yöntem daha verimlidir ve gereksiz döngüleri önler.

Mantığı doğrudan Inserted tablosu ile birleştirecek şekilde değiştirin:

CREATE TRIGGER [dbo].[tblMenuItemInsertSecurity] ON [dbo].[tblMenuItems] 
FOR INSERT
AS
BEGIN
    INSERT INTO tblRestrictedMenuItems ([RoleID], [MenuItemID], [RestrictLevel])
    SELECT u.[ID], i.[ID], 1
    FROM tblUserRoles u
    JOIN Inserted i ON <eğer gerekiyorsa bir koşul>
END

Bu kod parçası, Inserted tablosundaki her satır için ilgili sayıda kaydın tblRestrictedMenuItems tablosuna eklenmesini sağlar.

Sonuç

Tetikleyicilerin davranışını anlamak ve Inserted sahte tablosunu düzgün bir şekilde kullanmak, SQL Server 2005 tetikleyicilerinizin birden fazla kayıt eklemesiyle etkin bir şekilde çalışmasını sağlar. Optimal performans için belirli bağlamınıza göre iteratif veya set-tabana dayalı yaklaşımlar arasında seçim yapın.

Yukarıda belirtildiği gibi tetikleyicinizi revize etmek için adımları izlerseniz, artık beklenen davranışı görmeli ve ana tabloda toplu eklemeler yaptığınızda hedef tablonuza birden fazla kaydın eklendiğini görmelisiniz.