2009-10-07 29 views
21

Tôi đã kích hoạt sau trên một bảng cho một cơ sở dữ liệu SQL Server 2008. Đó là đệ quy, vì vậy tôi cần phải dừng lại.Làm cách nào để ngăn trình kích hoạt cơ sở dữ liệu đệ quy?

Sau khi tôi chèn hoặc cập nhật bản ghi, tôi đang cố cập nhật một trường đơn lẻ trên bảng đó.

Dưới đây là cò:

ALTER TRIGGER [dbo].[tblMediaAfterInsertOrUpdate] 
    ON [dbo].[tblMedia] 
    BEFORE INSERT, UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON 

    DECLARE @IdMedia INTEGER, 
     @NewSubject NVARCHAR(200) 

    SELECT @IdMedia = IdMedia, @NewSubject = Title 
    FROM INSERTED 

    -- Now update the unique subject field. 
    -- NOTE: dbo.CreateUniqueSubject is my own function. 
    --  It just does some string manipulation. 
    UPDATE tblMedia 
    SET UniqueTitle = dbo.CreateUniqueSubject(@NewSubject) + 
         CAST((IdMedia) AS VARCHAR(10)) 
    WHERE tblMedia.IdMedia = @IdMedia 
END 

bất cứ ai có thể cho tôi biết làm thế nào tôi có thể ngăn chặn chèn của cò từ đá tắt kích hoạt một lần nữa?

+0

Một số người đã nói để vô hiệu hóa kích hoạt đệ quy. ngay bây giờ, tôi sẽ không muốn chạm vào thiết lập đó. Tôi thích sửa lỗi tsql. –

+0

Sau đó, những khoảng trống kích hoạt không nên TRƯỚC KHI một bộ kích hoạt INSTEAD OF? http://msdn.microsoft.com/en-us/library/ms175089.aspx –

Trả lời

1

Bạn có thể có cột NULLABLE riêng biệt cho biết liệu UniqueTitle đã được đặt chưa.

Set nó vào giá trị thực sự trong một kích hoạt, và có kích hoạt không làm gì cả nếu nó là giá trị đúng trong "chèn"

+0

Tại sao bỏ phiếu xuống? – DVK

30

tôi thấy ba khả năng:

  1. Disable cò đệ quy:

    Điều này sẽ ngăn chặn trình kích hoạt được kích hoạt để gọi một trình kích hoạt khác hoặc tự gọi lại. Để làm điều này, thực hiện lệnh này:

    ALTER DATABASE MyDataBase SET RECURSIVE_TRIGGERS OFF 
    GO 
    
  2. Sử dụng một kích hoạt THAY UPDATE, INSERT

    Sử dụng một kích hoạt INSTEAD OF bạn có thể kiểm soát bất kỳ cột đang được cập nhật/chèn, và thậm chí thay thế trước khi gọi chỉ huy.

  3. kiểm soát kích hoạt bằng cách ngăn chặn sử dụng NẾU CẬP NHẬT

    Kiểm tra cột sẽ cho bạn với độ chính xác hợp lý nếu bạn kích hoạt được tự xưng. Để thực hiện điều này sử dụng mệnh đề IF UPDATE() như:

    ALTER TRIGGER [dbo].[tblMediaAfterInsertOrUpdate] 
        ON [dbo].[tblMedia] 
        FOR INSERT, UPDATE 
    AS 
    BEGIN 
        SET NOCOUNT ON 
        DECLARE @IdMedia INTEGER, 
         @NewSubject NVARCHAR(200) 
    
        IF UPDATE(UniqueTitle) 
         RETURN; 
    
        -- What is the new subject being inserted? 
        SELECT @IdMedia = IdMedia, @NewSubject = Title 
        FROM INSERTED 
    
        -- Now update the unique subject field. 
        -- NOTE: dbo.CreateUniqueSubject is my own function. 
        --  It just does some string manipulation. 
        UPDATE tblMedia 
        SET UniqueTitle = dbo.CreateUniqueSubject(@NewSubject) + 
             CAST((IdMedia) AS VARCHAR(10)) 
        WHERE tblMedia.IdMedia = @IdMedia 
    END 
    
+0

Câu hỏi nhanh. Bạn đang sử dụng _BEFORE_ thay vì _AFTER_. Điều này vẫn sẽ cung cấp cho tôi giá trị ID mới được chèn (Identity)? Hay điều đó chỉ được tạo trên một _AFTER_ ?? –

+0

Đã sửa lỗi. Kích hoạt trình kích hoạt sau khi chèn/cập nhật – Rodrigo

+0

Không - không hoạt động. Tôi đang làm một chèn nhưng Cập nhật (UniqueTitle) phải nghĩ rằng đó là một bản cập nhật ... ??? –

7
ALTER DATABASE <dbname> SET RECURSIVE_TRIGGERS OFF 

RECURSIVE_TRIGGERS { ON | OFF }

ON bắn Recursive của SAU gây nên được cho phép.

TẮT Chỉ cho phép kích hoạt đệ quy trực tiếp của trình kích hoạt SAU. Để cũng vô hiệu hóa đệ quy gián tiếp trình kích hoạt SAU, hãy đặt tùy chọn máy chủ kích hoạt lồng nhau thành 0 bằng cách sử dụng sp_configure.

Chỉ đệ quy trực tiếp được ngăn chặn khi RECURSIVE_TRIGGERS được đặt thành TẮT. Để vô hiệu hóa đệ quy gián tiếp, bạn cũng phải đặt các trình kích hoạt lồng nhau tùy chọn máy chủ thành 0.

Tình trạng của tùy chọn này có thể được xác định bằng cách kiểm tra cột is_recursive_triggers_on trong danh mục sys.databases xem hoặc tài sản của chức năng DATABASEPROPERTYEX IsRecursiveTriggersEnabled.

5

Tôi nghĩ rằng tôi đã nhận nó :)

Khi tiêu đề là nhận 'cập nhật' (đọc: chèn hoặc cập nhật), sau đó cập nhật các đối tượng độc đáo. Khi kích hoạt được chạy lần thứ hai, trường uniquesubject sẽ được cập nhật, vì vậy nó dừng lại và để lại trigger.

Ngoài ra, tôi đã làm cho nó xử lý NHIỀU hàng được thay đổi -> Tôi luôn quên điều này bằng trình kích hoạt.

ALTER TRIGGER [dbo].[tblMediaAfterInsert] 
    ON [dbo].[tblMedia] 
    FOR INSERT, UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON 

    -- If the Title is getting inserted OR updated then update the unique subject. 
    IF UPDATE(Title) BEGIN 
     -- Now update all the unique subject fields that have been inserted or updated. 
     UPDATE tblMedia 
     SET UniqueTitle = dbo.CreateUniqueSubject(b.Title) + 
          CAST((b.IdMedia) AS VARCHAR(10)) 
     FROM tblMedia a 
      INNER JOIN INSERTED b on a.IdMedia = b.IdMedia 
    END 
END 
+0

Tôi không chắc tại sao điều này đã được downvoted bởi bất cứ ai, nó là một giải pháp khá hữu ích. –

0

Vì mục đích đầy đủ, tôi sẽ thêm một vài điều. Nếu bạn có một đặc biệt sau khi kích hoạt mà bạn chỉ muốn chạy một lần, bạn có thể thiết lập nó để chạy cuối cùng bằng cách sử dụng sp_settriggerorder.

Tôi cũng sẽ xem xét nếu nó có thể không được tốt nhất để kết hợp các kích hoạt đang làm đệ quy vào một kích hoạt.

41

Không chắc chắn nếu nó là thích hợp cho câu hỏi của OP nữa, nhưng trong trường hợp bạn đã đến đây để tìm hiểu làm thế nào để ngăn chặn đệ quy hoặc đệ quy lẫn nhau xảy ra trong một kích hoạt, bạn có thể kiểm tra cho điều này như sau:

IF TRIGGER_NESTLEVEL() <= 1/*this update is not coming from some other trigger*/ 

MSDN link

+5

Đây thực sự là câu trả lời hay nhất và câu trả lời trực tiếp nhất cho câu hỏi của người đăng. – Curt

+0

có điều này phải là câu trả lời. thanks –

+1

Khi câu trả lời thực sự tuyên bố, điều này cũng ngăn chặn kích hoạt kích hoạt nếu cập nhật đến từ một số kích hoạt khác. Nhưng đó không phải là đệ quy. Phép đệ quy xảy ra khi bản cập nhật xuất hiện cùng một trigger. Trong trường hợp đó, bạn cần truyền id đối tượng cho hàm: https://stackoverflow.com/a/47074365/150342 – Colin

1

TRIGGER_NESTLEVEL thể được sử dụng để ngăn chặn đệ quy của một kích hoạt cụ thể, nhưng điều quan trọng là phải vượt qua các đối tượng id của cò vào hàm. Nếu không, bạn cũng sẽ ngăn chặn sự kích hoạt từ bắn khi chèn hoặc cập nhật được thực hiện bởi kích hoạt khác:

IF TRIGGER_NESTLEVEL(OBJECT_ID('dbo.mytrigger')) > 1 
     BEGIN 
      PRINT 'mytrigger exiting because TRIGGER_NESTLEVEL > 1 '; 
      RETURN; 
    END; 

Từ MSDN:

Khi không có tham số được chỉ định, TRIGGER_NESTLEVEL trả về tổng số trigger trên ngăn xếp cuộc gọi. Điều này bao gồm chính nó.

tham khảo: Avoiding recursive triggers

Các vấn đề liên quan