Chỉ kích hoạt cập nhật SQL khi cột được sửa đổi


101

Bằng cách xem xét các ví dụ khác, tôi đã nghĩ ra những điều sau đây nhưng nó có vẻ không hoạt động như tôi muốn: Tôi muốn nó chỉ cập nhật thông tin đã sửa đổi nếu QtyToRepairgiá trị đã được cập nhật ... nhưng nó không hoạt động cái đó.

Nếu tôi nhận xét về nơi thì thông tin sửa đổi được cập nhật trong mọi trường hợp. Như tôi đã nói những ví dụ khác khiến tôi lạc quan. Bất kỳ manh mối nào được đánh giá cao. Cảm ơn.

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
Một cảnh báo về update()- nó chỉ kiểm tra nếu cột xuất hiện trong danh sách cập nhật và luôn đúng với các lần chèn. Nó không kiểm tra xem giá trị cột đã thay đổi hay chưa, vì bạn có thể có nhiều hơn một hàng, trong đó một số giá trị đã thay đổi và một số thì không.
Nikola Markovinović

Câu trả lời:


128

Bạn có hai cách cho câu hỏi của mình:

1- Sử dụng Lệnh cập nhật trong Trình kích hoạt của bạ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- Sử dụng Tham gia giữa bảng đã chèn và bảng đã xóa

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

Khi bạn sử dụng lệnh cập nhật cho bảng SCHEDULEvà Đặt QtyToRepairCột thành giá trị mới, nếu giá trị mới bằng giá trị cũ trong một hoặc nhiều hàng, giải pháp 1 cập nhật tất cả hàng đã cập nhật trong bảng Lịch biểu nhưng giải pháp 2 cập nhật chỉ lập lịch cho các hàng mà giá trị cũ không bằng mới giá trị.


Xin lỗi vì đã không đề cập rằng đó là SQLServer. Tôi cần sử dụng bảng đã xóa. Cuối cùng tôi đã viết vào một bảng riêng (để duy trì lịch sử).
Walter de Jong

9
Phương pháp tiếp cận số 2 tốt hơn, nếu bạn không muốn trình kích hoạt của mình kích hoạt nếu cột được thay đổi thành cùng một giá trị.
Neolisk

2
Tôi nghĩ rằng tôi có thể thiếu một cái gì đó - nhưng cách tiếp cận số 1 sẽ không hoạt động, vì đây là sau khi cập nhật, vì vậy hàng hiện tại sẽ luôn có cùng giá trị với hàng chèn. Bạn phải tham gia để xóa nếu bạn đang sử dụng sau khi cập nhật
Rob

5
@Rob Câu lệnh "IF UPDATE" đang gọi một thủ tục có quyền truy cập vào danh sách cột gồm các cột đã được cập nhật như một phần của truy vấn và do đó không cần biết các giá trị trước đó. (Chúng tôi chỉ cần chạy vào này trong môi trường của chúng tôi và khẳng định rằng "NẾU UPDATE" được vinh danh không phụ thuộc vào "SAU KHI UPDATE" khoản)
TChadwick

3
tại sao bạn tham gia insertedbảng trong truy vấn thứ hai? nó phải giống như bảng, phải không?
teran

22

fyi Đoạn mã tôi đã kết thúc với:

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
Tôi thấy điều này hữu ích vì câu trả lời 2- Sử dụng Nối giữa ở trên không bao giờ hoạt động do tiêu chí WHERE S.QtyToRepair <> I.QtyToRepair AND D.QtyToRepair <> I.QtyToRepairkhông bao giờ kích hoạt / đối sánh vì tiêu chí đầu tiên không bao giờ đúng - bảng được chèn luôn khớp với giá trị bảng thực tế. Sử dụng `WHERE I.QtyToRepair <> D.QtyToRepair` là chìa khóa cho tôi. Ngoài ra, sự IF UPDATE (field)trợ giúp từ nhiều trình kích hoạt đang kích hoạt.
Firegarden

13

Người ta nên kiểm tra xem có QtyToRepairđược cập nhật lúc đầu không.

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

Bạn muốn làm như sau:

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

Xin lưu ý rằng trình kích hoạt này sẽ kích hoạt mỗi khi bạn cập nhật cột cho dù giá trị có giống nhau hay không.


2

Bất cứ khi nào một bản ghi được cập nhật, một bản ghi sẽ bị "xóa". Đây là ví dụ của tôi:

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

Nó hoạt động tốt

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.