2009-01-30 16 views
15

Esta pregunta es muy similar a SQL Server 2005: T-SQL to temporarily disable a triggerMSSQL: Desactivar desencadena por un INSERT

Sin embargo no quiero desactivar todos los disparadores y ni siquiera por un lote de comandos, pero sólo por un único inserto.

Tengo que lidiar con un sistema de tienda donde el autor original puso una lógica de aplicación en un disparador (¡mala idea!). Esa lógica de aplicación funciona bien siempre y cuando no intente insertar datos de otra manera que la "interfaz de administración" original. Mi trabajo es escribir una herramienta para "importar desde el sistema de etapas", así que tengo todos los datos listos. Cuando intento insertarlo, el disparador sobrescribe el Código de producto existente (¡no el ID numérico de IDENTIDAD!) Con el código generado. Para generar el Código, utiliza el ID autogenerado de una inserción en otra tabla, de modo que ni siquiera puedo trabajar con la @@ IDENTIDAD para encontrar la columna que acaba de insertar y ACTUALIZAR la fila insertada con el Código del producto real.

Cualquier forma que yo pueda para evitar un código incómodo (inserte algunos caracteres aleatorios en el nombre del producto y luego intente encontrar la fila con los caracteres aleatorios para actualizarlo).

Entonces: ¿Hay alguna manera de desactivar los activadores (incluso uno solo) para solo uno INSERTAR?

+1

La publicación de Kristof tiene un par de soluciones que parecen ser capaces de resolver su problema, solo quería informarle en caso de que esté dispuesto a cambiar su respuesta aceptada a esa. – SqlRyan

Respuesta

12

Puede desactivar los disparadores en una mesa usando:

ALTER TABLE MyTable DISABLE TRIGGER ALL 

Pero que lo haría para todas las sesiones, no sólo su conexión actual .. lo que obviamente es una muy mala cosa que hacer :-)

La mejor manera sería alterar el disparador por sí mismo para que tome la decisión si necesita ejecutarse, ya sea con un indicador de "tipo de inserción" en la tabla o algún otro medio si ya está almacenando un tipo de algún tipo .

+3

" que obviamente es algo muy malo de hacer "-> que es por lo que no quiero hacerlo;) – BlaM

+1

Bueno ... no lo hagas entonces;) –

+2

Me alegro de que todos estamos de acuerdo en eso;) – andynormancx

1

¿Puede verificar SUSER_SNAME() y solo ejecutarlo en contexto de la interfaz de administración?

+0

Solo se utiliza un usuario para acceder a la base de datos. Así que desafortunadamente: No. – BlaM

5

En lugar de deshabilitar los desencadenantes, no puede cambiar el comportamiento del desencadenador. Agregue una nueva columna anulable a la tabla en cuestión llamada "insertedFromImport".

En el desencadenador, cambie el código para que el bit ofensivo del desencadenador solo se ejecute en filas donde "insertFromImport" es nulo. Cuando inserta sus registros, establezca "insertFromImport" en algo que no sea nulo.

+0

Realmente me gustó este, ya que era muy limpio. Sin embargo, lo alteré ligeramente para comprobar también si esta columna se actualizó, lo que ejecutó el disparador para otras actualizaciones de la tabla 'IF NOT (UPDATE (insertFromImport) Y EXISTS (SELECT insertFromImport FROM INSERTED WHERE insertedFromImport IS NOT NULL)) BEGIN' –

15

Es posible resultado útil:

Disabling a Trigger for a Specific SQL Statement or Session

Pero hay otro problema que usted puede hacer frente también. Si entiendo la situación en la que se encuentra correctamente, su sistema inserta automáticamente el código de producto (generando el valor). Ahora debe insertar un producto que fue creado por un sistema de etapas, y para ese producto su código de producto fue creado por el sistema de etapas y desea insertarlo manualmente en el sistema en vivo.

Si realmente tiene que hacerlo, debe asegurarse de que los códigos generados por su aplicación en vivo en el futuro no entren en conflicto con el código que insertó manualmente, supongo que deben ser únicos.

Otro enfoque es permitir que el sistema genere el nuevo código y sobrescribir los datos correspondientes si es necesario.

+0

En realidad, el objetivo final es deshabilitar por completo las funciones de edición en el sistema de producción. ¡De lo contrario, la nota sobre las colisiones de código es muy buena! – BlaM

0

Si inserta utilizando BULK INSERT, puede deshabilitar los desencadenantes solo para la inserción.

Estoy bastante seguro de que la inserción masiva requerirá un archivo de datos en el sistema de archivos para importar, por lo que no puede usar T-SQL.

Para usar BULK INSERT necesita permisos INSERT y ADMINISTRATOR BULK OPERATION. Si deshabilita los factores desencadenantes o las restricciones, también necesitará el permiso ALTER TABLE.

Si está utilizando la autenticación de Windows, su usuario de Windows necesitará acceso de lectura desde el archivo. si usa la autenticación de modo mixto, la cuenta del servicio de servidor SQl necesita acceso de lectura desde el archivo.

Al importar utilizando BULK IMPORT, los activadores están deshabilitados de forma predeterminada.

Más información: http://msdn.microsoft.com/en-us/library/ms188365.aspx

1

Veo muchas cosas que podrían crear un problema. Primero cambie el disparador para considerar múltiples importaciones de registros. Eso probablemente pueda solucionar tu problema. NO apague el gatillo ya que está apagado para todos, no solo usted. Si debe, entonces, poner la base de datos en el modo de usuario de usuario único antes de hacerlo y realizar su tarea fuera de horario.

¡A continuación, bajo ninguna circunstancia use @@ identity para obtener el valor recién insertado! USe scope_identity en su lugar. @@ identity devolverá el valor incorrecto si hay desencadenantes en la tabla que también inserten en otras tablas con campos de identidad. Si está usando @@ identity ahora mismo a través de su sistema (ya que sabemos que su sistema tiene activadores), su primera prioridad abosolute debe ser encontrar y cambiar inmediatamente todas las instancias de @@ identity en su código. Si no lo hace, puede tener serios problemas de integridad de datos. Este es un tipo de problema de "detener todo el trabajo hasta que esto se solucione".

En cuanto a obtener la información que acaba de insertar, considere crear un lote como parte de su inserción y luego agregue una columna llamada lote (que puede contener nulos para que no afecte a otras inserciones) a la tabla. Luego puede devolverle la llamada a lo que insertó por lotes.

+0

Gracias por la sugerencia con SCOPE_IDENTITY. Vengo de "oldschool" SQL Server 2000 (y anterior) que no tenía eso. :) – BlaM

4

Desactivar el desencadenador, insertar, confirmar.

SET IDENTITY_INSERT Test ON 
GO 

BEGIN TRAN 

DISABLE TRIGGER trg_Test ON Test 

INSERT INTO Test (MyId, MyField) 
    VALUES (999, 'foo') 

ENABLE TRIGGER trg_Test ON Test 

COMMIT TRAN 

SET IDENTITY_INSERT Test OFF 
GO 
Cuestiones relacionadas