2009-10-07 5 views
21

У меня есть следующий триггер для таблицы для базы данных SQL Server 2008. Это рекурсия, поэтому мне нужно остановить ее.Как предотвратить повторный запуск триггера базы данных?

После того, как я вставляю или обновляю запись, я пытаюсь просто обновить одно поле в этой таблице.

Вот триггер:

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 

Может кто-нибудь сказать мне, как я могу предотвратить вставку триггера от сбрасывая другой триггер снова?

+0

Ряд людей сказали, чтобы отключить триггер рекурсию. прямо сейчас, я не хочу прикасаться к этой настройке. Я предпочитаю фиксировать tsql. –

+0

Затем следует, что триггер не должен быть ПЕРЕД, но триггер INSTEAD OF? http://msdn.microsoft.com/en-us/library/ms175089.aspx –

ответ

1

У вас может быть отдельный столбец NULLABLE, указывающий, был ли установлен UniqueTitle.

Установите его истинное значение в качестве триггера, и есть триггер ничего не делать, если это значение истинно в «ВСТАВИТЬ»

+0

Почему при голосовании? – DVK

30

Я вижу три возможности:

  1. Отключить триггер рекурсии:

    Это предотвратит срабатывание триггера, чтобы вызвать другой триггер или снова вызвать себя. Для этого необходимо выполнить следующую команду:

    ALTER DATABASE MyDataBase SET RECURSIVE_TRIGGERS OFF 
    GO 
    
  2. использовать триггер INSTEAD OF UPDATE, INSERT

    Использование INSTEAD OF триггера вы можете контролировать любой столбец обновляется/вставляется, и даже замена перед вызовом команда.

  3. управления триггером путем предотвращения использования IF UPDATE

    Тестирование колонка покажет вам с разумной точностью, если вы вызываете вызывает себя. Для этого используйте пункт IF UPDATE() как:

    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

Быстрый вопрос. Используйте _BEFORE_ вместо _AFTER_. Будет ли это еще давать мне новое значение ID Inserted (Identity)? Или это создается только на _AFTER_ ?? –

+0

Исправлено. Пожар триггера после вставки/обновления – Rodrigo

+0

Нет - не работает. Я делаю вставку, но Update (UniqueTitle) должен думать, что это обновление ... ??? –

7
ALTER DATABASE <dbname> SET RECURSIVE_TRIGGERS OFF 

RECURSIVE_TRIGGERS { ON | OFF }

НА рекурсивных обжиге ПОСЛЕ триггеров допускается.

OFF Запрещается только прямой рекурсивный запуск триггеров AFTER. К также отключить непрямую рекурсию ПОСЛЕ триггеров установите для параметра сервера триггеров вложенных значение 0, используя sp_configure.

Запрещается только прямая рекурсия, когда для параметра RECURSIVE_TRIGGERS установлено значение OFF. Чтобы отключить косвенную рекурсию, вы также должны установить вложенные триггеры в 0.

Состояние этого параметра можно определить, исследуя колонку is_recursive_triggers_on в представлении каталога sys.databases или IsRecursiveTriggersEnabled свойство функция DATABASEPROPERTYEX.

5

Я думаю, что я получил его :)

Когда название становится «обновленный» (читай: вставляемые или изменяемые), а затем обновить уникальный объект. Когда триггер запускается во второй раз, поле uniquesubject обновляется, поэтому он останавливается и покидает триггер.

Кроме того, я заставил его обрабатывать многострочные строки, которые меняются -> Я всегда забываю об этом с помощью триггеров.

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

Я не уверен, почему это было ниспровергнуто кем угодно, это довольно полезное решение. –

0

Для полной цели я добавлю несколько вещей. Если у вас есть определенный после триггера, который вы хотите запустить только один раз, вы можете настроить его для последнего запуска, используя sp_settriggerorder.

Я бы также подумал, не лучше ли комбинировать триггеры, которые выполняют рекурсию в один триггер.

41

Не уверен, если это уместно на вопрос ФП в больше, но в случае, если вы пришли сюда, чтобы узнать, как предотвратить рекурсию или взаимную рекурсию от происходящего в триггере, вы можете проверить это, например, так:

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

MSDN link

+5

Это на самом деле лучший ответ, и тот, который наиболее непосредственно отвечает на вопрос плаката. – Curt

+0

Да, это должен быть ответ. спасибо –

+1

Как на самом деле отвечает, это также предотвращает запуск триггера, если обновление происходит от какого-либо другого триггера. Но это не рекурсия. Рекурсия происходит, когда обновление приходит с одним и тем же триггером. В этом случае вам необходимо передать идентификатор объекта функции: https://stackoverflow.com/a/47074365/150342 – Colin

1

TRIGGER_NESTLEVEL может быть использован для предотвращения рекурсии определенного триггера, но важно, чтобы передать идентификатор объекта триггера в функцию. В противном случае вы также предотвратить курок от стрельбы, когда вставка или обновление производится другим триггером:

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

От MSDN:

Когда не указаны параметры, TRIGGER_NESTLEVEL возвращает общее число триггеров в стеке вызовов. Это включает в себя.

Ссылка: Avoiding recursive triggers

Смежные вопросы