2009-10-07 7 views
21

Tengo el siguiente disparador en una tabla para una base de datos de SQL Server 2008. Está recurriendo, así que tengo que detenerlo.¿Cómo evito que una activación de la base de datos vuelva a activarse?

Después de insertar o actualizar un registro, intento simplemente actualizar un solo campo en esa tabla.

Aquí es el gatillo:

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 

¿Puede alguien decirme cómo puedo evitar la inserción del activador desde dando inicio a otro factor desencadenante de nuevo?

+0

Un número de personas han dicho a deshabilitar la recursividad gatillo. en este momento, no voy a querer tocar esa configuración. Prefiero reparar el tsql. –

+0

Entonces pegar el disparador no debe ser ANTES sino un gatillo INSTEAD OF? http://msdn.microsoft.com/en-us/library/ms175089.aspx –

Respuesta

1

Puede tener una columna NULLABLE separada que indique si se configuró UniqueTitle.

ponemos a true valor en un gatillo, y tienen el gatillo no hacen nada si su valor es cierto en "insertada"

+0

¿Por qué votar abajo? – DVK

30

veo tres posibilidades:

  1. recursividad gatillo Desactivar:

    Esto evitará que un disparador disparado llame a otro activador o se llame de nuevo. Para ello, ejecute este comando:

    ALTER DATABASE MyDataBase SET RECURSIVE_TRIGGERS OFF 
    GO 
    
  2. Usar un disparador EN LUGAR DE actualizar, insertar

    El uso de un disparador INSTEAD OF puede controlar cualquier columna que se actualiza/insertada, e incluso la sustitución antes de llamar al mando.

  3. control del gatillo, impidiendo el uso de IF UPDATE

    Prueba de la columna le dirá con una exactitud razonable si disparador se hace llamar. Para ello utiliza la cláusula IF UPDATE() como:

    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

Pregunta rápida. Estás usando _BEFORE_ en lugar de _AFTER_. ¿Esto todavía me dará el nuevo valor de ID Insertado (Identidad)? ¿O solo se crea en un _AFTER_ ?? –

+0

Reparado. Dispare el gatillo después de insertar/actualizar – Rodrigo

+0

No, no funciona. Estoy haciendo una inserción, pero la actualización (UniqueTitle) debe pensar que es una actualización ... ??? –

7
ALTER DATABASE <dbname> SET RECURSIVE_TRIGGERS OFF 

RECURSIVE_TRIGGERS { ON | OFF }

EN tiro recursiva de disparadores Después de dejar.

OFF Solo se permite el disparo recursivo directo de desencadenadores AFTER. Para también deshabilite la recursión indirecta de los activadores DESPUÉS, configure la opción del servidor de activadores anidados en 0 utilizando sp_configure.

Solo se evita la recursividad directa cuando RECURSIVE_TRIGGERS está establecido en OFF. Para deshabilitar la recursión indirecta, también debe establecer la opción del servidor activadores anidados en 0.

El estado de esta opción se puede determinar mediante el examen de la columna de la is_recursive_triggers_on en la vista de catálogo sys.databases o la propiedad IsRecursiveTriggersEnabled de la función DATABASEPROPERTYEX.

5

creo que lo tengo :)

Cuando el título se está 'actualizado' (léase: inserta o se actualiza), a continuación, actualizar el tema único. Cuando el desencadenante se ejecuta por segunda vez, el campo de tema único se actualiza, por lo que se detiene y deja el desencadenador.

Además, lo he hecho manejar MÚLTIPLES filas que se cambian -> Siempre me olvido de esto con los factores desencadenantes.

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

No estoy seguro de por qué esto fue votado por cualquiera, es una solución bastante útil. –

0

Para completar, añadiré algunas cosas. Si tiene un activador posterior particular que solo desea ejecutar una vez, puede configurarlo para que se ejecute último utilizando sp_settriggerorder.

También consideraría si no fuera mejor combinar los disparadores que están haciendo la recursividad en un disparador.

41

No estoy seguro si es pertinente a la pregunta del OP más, pero en caso de que usted vino aquí para averiguar cómo evitar la repetición o recursión mutua suceda en un disparador, puede probar para este modo:

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

MSDN link

+5

Esta es en realidad la mejor respuesta y la que responde más directamente a la pregunta del afiche. – Curt

+0

sí, esta debería ser la respuesta. gracias –

+1

Como realmente dice la respuesta, esto también evita que el disparador se dispare si la actualización proviene de algún otro disparador. Pero eso no es recursividad. La recursión ocurre cuando la actualización proviene del mismo disparador. En ese caso, debe pasar la identificación del objeto a la función: https://stackoverflow.com/a/47074365/150342 – Colin

1

TRIGGER_NESTLEVEL se puede utilizar para evitar la recursión de un disparador específico, pero es importante para pasar el ID de objeto del gatillo en la función. De lo contrario, también puede evitar que el gatillo de disparo durante una inserción o actualización es hecha por otro factor desencadenante:

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

De MSDN:

Cuando se especifica ningún parámetro, TRIGGER_NESTLEVEL devuelve el total de número de disparadores en la pila de llamadas. Esto incluye a sí mismo.

Referencia: Avoiding recursive triggers

Cuestiones relacionadas