SQL güncellemesi yalnızca sütun değiştirildiğinde tetiklenir


101

Diğer örneklere bakarak aşağıdakileri buldum, ancak istediğim gibi çalışmıyor: QtyToRepairDeğer güncellendiyse yalnızca değiştirilen bilgileri güncellemesini istiyorum ... ama yapmıyor bu.

Nerede olduğunu açıklarsam, değiştirilen bilgiler her durumda güncellenir. Dediğim gibi diğer örnekler beni iyimser hissettirdi. Herhangi bir ipucu takdir edildi. Teşekkürler.

Walter

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    UPDATE SCHEDULE SET modified = GETDATE()
        , ModifiedUser = SUSER_NAME()
        , ModifiedHost = HOST_NAME()
    FROM SCHEDULE S
    INNER JOIN Inserted I on S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
    WHERE S.QtyToRepair <> I.QtyToRepair
END

8
Hakkında bir uyarı update()- yalnızca sütunun güncelleme listesinde görünüp görünmediğini test eder ve eklemeler için her zaman geçerlidir. Sütun değerinin değişip değişmediğini kontrol etmez, çünkü birden fazla satırınız olabilir, burada bazı değerlerin değiştiği ve bazılarının değişmediği.
Nikola Markovinović

Yanıtlar:


128

Sorunuz için iki yolunuz var:

1- Tetikleyicinizde Güncelleme Komutunu kullanın.

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS BEGIN
    SET NOCOUNT ON;
    IF UPDATE (QtyToRepair) 
    BEGIN
        UPDATE SCHEDULE 
        SET modified = GETDATE()
           , ModifiedUser = SUSER_NAME()
           , ModifiedHost = HOST_NAME()
        FROM SCHEDULE S INNER JOIN Inserted I 
        ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
        WHERE S.QtyToRepair <> I.QtyToRepair
    END 
END

2- Eklenen tablo ile silinen tablo arasında Birleştirme kullanın

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS BEGIN
    SET NOCOUNT ON;    

    UPDATE SCHEDULE 
    SET modified = GETDATE()
       , ModifiedUser = SUSER_NAME()
       , ModifiedHost = HOST_NAME()
    FROM SCHEDULE S 
    INNER JOIN Inserted I ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
    INNER JOIN Deleted D ON S.OrderNo = D.OrderNo and S.PartNumber = D.PartNumber                  
    WHERE S.QtyToRepair <> I.QtyToRepair
    AND D.QtyToRepair <> I.QtyToRepair
END

Tablo için güncelleme komutunu SCHEDULEve QtyToRepairSütunu Ayarla komutunu kullandığınızda , yeni değer bir veya çok satırdaki eski değere eşitse, çözüm 1 Zamanlama tablosundaki tüm güncellenmiş satırı günceller ancak çözüm 2 yalnızca eski değerin yeniye eşit olmayan satırları günceller değer.


SQLServer olduğundan bahsetmediğim için özür dilerim. Silinen tabloyu kullanmam gerekiyordu. Sonunda ayrı bir masaya yazdım (bir geçmişi korumak için).
Walter de Jong

9
Sütun aynı değere değiştirilirse tetikleyicinizin tetiklenmesini istemiyorsanız, yaklaşım 2 daha iyidir.
Neolisk

2
Sanırım bir şeyi kaçırıyor olabilirim - ancak 1 numaralı yaklaşım işe yaramaz, çünkü bu güncellemeden sonra , bu yüzden mevcut satır her zaman ekleme satırı ile aynı değere sahip olacaktır. Sen gerekir Eğer güncellemeden sonra kullanıyorsanız silindi katılmak
Rob

5
@Rob "IF UPDATE" ifadesi, sorgunun bir parçası olarak güncellenen sütunların bir sütun listesine erişimi olan ve dolayısıyla önceki değerleri bilmesine gerek olmayan bir prosedürü çağırıyor. (Bu
konuyla az önce çevremizde karşılaştık

3
neden insertedikinci sorguda tabloya katılıyorsunuz ? masanın kendisi ile aynı olmalı, değil mi?
teran

22

fyi Bulduğum kod:

IF UPDATE (QtyToRepair)
    begin
        INSERT INTO tmpQtyToRepairChanges (OrderNo, PartNumber, ModifiedDate, ModifiedUser, ModifiedHost, QtyToRepairOld, QtyToRepairNew)
        SELECT S.OrderNo, S.PartNumber, GETDATE(), SUSER_NAME(), HOST_NAME(), D.QtyToRepair, I.QtyToRepair FROM SCHEDULE S
        INNER JOIN Inserted I ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
        INNER JOIN Deleted D ON S.OrderNo = D.OrderNo and S.PartNumber = D.PartNumber 
        WHERE I.QtyToRepair <> D.QtyToRepair
end

1
Bunu yararlı buldum çünkü yukarıdaki 2- Bir Arada Kullan yanıtı WHERE S.QtyToRepair <> I.QtyToRepair AND D.QtyToRepair <> I.QtyToRepair, ilk ölçüt hiçbir zaman doğru olmadığı için hiçbir zaman tetiklenmediği / eşleşmediği için hiçbir zaman işe yaramadı - eklenen tablo her zaman gerçek tablo değeriyle eşleşti. `WHERE I.QtyToRepair <> D.QtyToRepair` kullanmak benim için anahtar oldu. Ayrıca IF UPDATE (field)birden fazla tetikleyicinin ateşlemesinden yardım.
Firegarden

13

QtyToRepairİlk önce güncellenip güncellenmediği kontrol edilmelidir .

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS 
BEGIN
SET NOCOUNT ON;
    IF UPDATE (QtyToRepair) 
    BEGIN
        UPDATE SCHEDULE 
        SET modified = GETDATE()
           , ModifiedUser = SUSER_NAME()
           , ModifiedHost = HOST_NAME()
        FROM SCHEDULE S INNER JOIN Inserted I 
            ON S.OrderNo = I.OrderNo and S.PartNumber =    I.PartNumber
        WHERE S.QtyToRepair <> I.QtyToRepair
    END
END

6

Aşağıdakileri yapmak istiyorsunuz:

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS 
BEGIN
SET NOCOUNT ON;

    IF (UPDATE(QtyToRepair))
    BEGIN
        UPDATE SCHEDULE SET modified = GETDATE()
            , ModifiedUser = SUSER_NAME()
            , ModifiedHost = HOST_NAME()
        FROM SCHEDULE S
        INNER JOIN Inserted I ON S.OrderNo = I.OrderNo AND S.PartNumber = I.PartNumber
        WHERE S.QtyToRepair <> I.QtyToRepair
    END
END

Değer aynı olsun ya da olmasın, sütunu her güncellediğinizde bu tetikleyicinin etkinleşeceğini lütfen unutmayın.


2

Bir kayıt her güncellendiğinde, bir kayıt "silinir". İşte benim örneğim:

ALTER TRIGGER [dbo].[UpdatePhyDate]
   ON  [dbo].[M_ContractDT1]
   AFTER UPDATE
AS 
BEGIN
    -- on ContarctDT1 PhyQty is updated 
    -- I want system date in Phytate automatically saved
    SET NOCOUNT ON;

    declare @dt1ky as int   

    if(update(Phyqty))
    begin
        select @dt1ky = dt1ky from deleted

        update M_ContractDT1 set PhyDate=GETDATE() where Dt1Ky=  @dt1ky     

    end

END

İyi çalışıyor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.