2009-10-07 5 views
21

Ho il seguente trigger su una tabella per un database SQL Server 2008. È ricorsivo, quindi ho bisogno di fermarlo.Come si impedisce l'insorgenza di un trigger del database?

Dopo aver inserito o aggiornato un record, sto tentando di aggiornare semplicemente un singolo campo su tale tabella.

Ecco il grilletto:

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 

qualcuno può dirmi come posso impedire che inserto del trigger dal dando il via un altro trigger di nuovo?

+0

Un certo numero di persone hanno detto di disabilitare grilletto ricorsione. adesso, non voglio toccare quell'impostazione. Preferisco sistemare il tsql. –

+0

Quindi peraps il trigger non dovrebbe essere PRIMA ma un trigger INSTEAD OF? http://msdn.microsoft.com/en-us/library/ms175089.aspx –

risposta

1

È possibile avere una colonna NULLABLE separata che indica se è stato impostato UniqueTitle.

Imposta a vero valore in un trigger, e hanno il grilletto non fanno nulla se il suo valore è vero in "inserito"

+0

Perché il down-vote? – DVK

30

vedo tre possibilità:

  1. Disabilita grilletto ricorsione:

    Ciò impedirà l'attivazione di un trigger per chiamare un altro trigger o richiamare se stesso. Per fare questo, eseguire questo comando:

    ALTER DATABASE MyDataBase SET RECURSIVE_TRIGGERS OFF 
    GO 
    
  2. utilizzare un trigger INVECE DI UPDATE, INSERT

    Utilizzando un trigger INSTEAD OF è possibile controllare qualsiasi colonna in fase di aggiornamento/inserimento, e anche la sostituzione prima di chiamare il comando.

  3. controllo il grilletto impedendo utilizzando IF UPDATE

    Test colonna vi dirà con una precisione ragionevole se Trigger è che si fa chiamare. Per fare questo uso della clausola IF UPDATE() come:

    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

Domanda veloce. Stai usando _BEFORE_ invece di _AFTER_. Questo mi darà ancora il nuovo valore ID inserito (Identità)? O viene creato solo su _AFTER_ ?? –

+0

corretto. Spara il grilletto dopo l'inserimento/aggiornamento – Rodrigo

+0

No - non funziona. Sto facendo un inserto ma l'aggiornamento (UniqueTitle) deve pensare che sia un aggiornamento ... ??? –

7
ALTER DATABASE <dbname> SET RECURSIVE_TRIGGERS OFF 

RECURSIVE_TRIGGERS { ON | OFF }

ON cottura ricorsiva di trigger AFTER è permesso.

OFF Solo l'attivazione ricorsiva diretta dei trigger AFTER non è consentita. Per disabilitare anche la ricorsione indiretta di triggerAFTER, impostare l'opzione del server di trigger nidificato su 0 utilizzando sp_configure.

Solo la ricorsione diretta viene impedita quando RECURSIVE_TRIGGERS è impostato su OFF. Per disabilitare la ricorsione indiretta, è necessario impostare l'opzione server dei trigger nidificati su 0 anche per .

Lo stato di questa opzione può essere determinata esaminando la colonna is_recursive_triggers_on nel sys.databases vista del catalogo o struttura IsRecursiveTriggersEnabled del funzione DATABASEPROPERTYEX.

5

Credo di aver capito :)

Quando il titolo è sempre 'aggiornato' (leggi: inserito o aggiornato), quindi aggiornare il soggetto unico. Quando il trigger viene eseguito una seconda volta, il campo di un oggetto unico viene aggiornato, quindi si arresta e lascia il trigger.

Inoltre, ho fatto gestire più file modificate -> Mi dimentico sempre di questo con i trigger.

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

Non so perché questo è stato downvoted da chiunque, è piuttosto una soluzione utile. –

0

Per completezza, aggiungerò alcune cose. Se si dispone di un particolare trigger dopo che si desidera eseguire solo una volta, è possibile configurarlo per l'ultimo utilizzo utilizzando sp_settriggerorder.

Vorrei anche considerare se potrebbe non essere il caso di combinare i trigger che stanno facendo la ricorsione in un trigger.

41

Non sono sicuro se è pertinente alla domanda del PO più, ma nel caso in cui sei venuto qui per scoprire come prevenire la ricorsione o ricorsione mutua accada in un trigger, è possibile verificare per questo in questo modo:

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

MSDN link

+5

Questa è in realtà la risposta migliore e quella che risponde più direttamente alla domanda del poster. – Curt

+0

sì questa dovrebbe essere la risposta. grazie –

+1

Come la risposta dice in realtà, questo impedisce anche l'attivazione del trigger se l'aggiornamento proviene da qualche altro trigger. Ma quella non è ricorsione. La ricorsione si verifica quando l'aggiornamento arriva dallo stesso trigger. In tal caso è necessario passare l'id oggetto alla funzione: https://stackoverflow.com/a/47074365/150342 – Colin

1

TRIGGER_NESTLEVEL può essere usato per impedire ricorsione di un trigger specifico, ma è importante passare l'id oggetto del grilletto nella funzione. In caso contrario, sarà anche impedire che il grilletto da sparo quando un inserimento o aggiornamento è fatto da un altro trigger:

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

Da MSDN:

Quando viene specificato alcun parametro, TRIGGER_NESTLEVEL restituisce il totale numero di trigger sullo stack delle chiamate. Questo include se stesso.

Riferimento: Avoiding recursive triggers