2012-08-27 19 views
70

Al mirar otros ejemplos he encontrado lo siguiente pero no parece funcionar como me gustaría: Quiero que actualice solo la información modificada si el valor QtyToRepair ha sido actualizado ... pero no hace eso.Activación de la actualización de SQL solo cuando se modifica la columna

Si hago un comentario en el que la información modificada se actualiza en todos los casos. Como dije, otros ejemplos me llevaron a ser optimista. Cualquier pista apreciada. Gracias.

Walter

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified] 
    ON [dbo].[SCHEDULE] 
    AFTER UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON; 

    UPDATE SCHEDULE SET modified = GETDATE() 
     , ModifiedUser = SUSER_NAME() 
     , ModifiedHost = HOST_NAME() 
    FROM SCHEDULE S 
    INNER JOIN Inserted I on S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber 
    WHERE S.QtyToRepair <> I.QtyToRepair 
END 
+1

Lo que DB está usando? –

+1

loooks like sql server –

+7

Una advertencia sobre 'update()' - solo prueba si la columna aparece en la lista de actualización, y siempre es cierta para las inserciones. No verifica si el valor de la columna ha cambiado, porque es posible que tenga más de una fila, donde algunos valores han cambiado y otros no. –

Respuesta

93

Se tienen dos vías para su pregunta:

1- Uso de comandos de actualización en su disparo.

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified] 
    ON [dbo].[SCHEDULE] 
    AFTER UPDATE 
AS BEGIN 
    SET NOCOUNT ON; 
    IF UPDATE (QtyToRepair) 
    BEGIN 
     UPDATE SCHEDULE 
     SET modified = GETDATE() 
      , ModifiedUser = SUSER_NAME() 
      , ModifiedHost = HOST_NAME() 
     FROM SCHEDULE S INNER JOIN Inserted I 
     ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber 
     WHERE S.QtyToRepair <> I.QtyToRepair 
    END 
END 

2- Uso de combinación entre la tabla y la tabla eliminada Insertado

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified] 
    ON [dbo].[SCHEDULE] 
    AFTER UPDATE 
AS BEGIN 
    SET NOCOUNT ON;  

    UPDATE SCHEDULE 
    SET modified = GETDATE() 
     , ModifiedUser = SUSER_NAME() 
     , ModifiedHost = HOST_NAME() 
    FROM SCHEDULE S 
    INNER JOIN Inserted I ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber 
    INNER JOIN Deleted D ON S.OrderNo = D.OrderNo and S.PartNumber = D.PartNumber     
    WHERE S.QtyToRepair <> I.QtyToRepair 
    AND D.QtyToRepair <> I.QtyToRepair 
END 

Cuando se utiliza comando de actualización para la tabla y SCHEDULE Conjunto QtyToRepair Columna de nuevo valor, si el nuevo valor igual al valor anterior en una o multi-fila, la solución 1 actualiza toda la fila actualizada en la tabla de programación, pero la actualización de la solución 2 solo programa las filas cuyo valor anterior no es igual al nuevo valor.

+0

Perdón por no mencionar que era SQLServer. Necesitaba usar la tabla eliminada. Terminé escribiendo en una tabla separada (para mantener un historial). –

+5

El enfoque n.º 2 es mejor, si no desea que su desencadenador se dispare si la columna se está cambiando al mismo valor. – Neolisk

+0

Creo que me puede estar perdiendo algo, pero el enfoque # 1 no funcionaría, porque esto es * después * de la actualización, por lo que la fila actual siempre tendrá el mismo valor que la fila de inserción. Usted * debe * unirse a eliminado si está usando después de la actualización – Rob

5

que quiere hacer lo siguiente:

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified] 
    ON [dbo].[SCHEDULE] 
    AFTER UPDATE 
AS 
BEGIN 
SET NOCOUNT ON; 

    IF (UPDATE(QtyToRepair)) 
    BEGIN 
     UPDATE SCHEDULE SET modified = GETDATE() 
      , ModifiedUser = SUSER_NAME() 
      , ModifiedHost = HOST_NAME() 
     FROM SCHEDULE S 
     INNER JOIN Inserted I ON S.OrderNo = I.OrderNo AND S.PartNumber = I.PartNumber 
     WHERE S.QtyToRepair <> I.QtyToRepair 
    END 
END 

Tenga en cuenta que este disparador se disparará cada vez que actualice la columna, no importa si el valor es el mismo o no.

11

Uno debe verificar si QtyToRepair se actualiza al principio.

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified] 
    ON [dbo].[SCHEDULE] 
    AFTER UPDATE 
AS 
BEGIN 
SET NOCOUNT ON; 
    IF UPDATE (QtyToRepair) 
    BEGIN 
     UPDATE SCHEDULE 
     SET modified = GETDATE() 
      , ModifiedUser = SUSER_NAME() 
      , ModifiedHost = HOST_NAME() 
     FROM SCHEDULE S INNER JOIN Inserted I 
      ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber 
     WHERE S.QtyToRepair <> I.QtyToRepair 
    END 
END 
10

FYI El código terminé con:

IF UPDATE (QtyToRepair) 
    begin 
     INSERT INTO tmpQtyToRepairChanges (OrderNo, PartNumber, ModifiedDate, ModifiedUser, ModifiedHost, QtyToRepairOld, QtyToRepairNew) 
     SELECT S.OrderNo, S.PartNumber, GETDATE(), SUSER_NAME(), HOST_NAME(), D.QtyToRepair, I.QtyToRepair FROM SCHEDULE S 
     INNER JOIN Inserted I ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber 
     INNER JOIN Deleted D ON S.OrderNo = D.OrderNo and S.PartNumber = D.PartNumber 
     WHERE I.QtyToRepair <> D.QtyToRepair 
end 
+1

Encontré esto útil porque la respuesta ** 2- Use Join between ** nunca funcionó debido a la donde los criterios 'WHERE S.QtyToRepair <> I.QtyToRepair Y D.QtyToRepair <> I.QtyToRepair' que nunca se activan/coinciden, dado que el primer criterio nunca fue verdadero, la tabla insertada siempre coincidía con el valor real de la tabla. Usar 'WHERE I.QtyToRepair <> D.QtyToRepair' fue la clave para mí. También la función 'IF UPDATE (field)' ayuda de disparos múltiples. – Firegarden

Cuestiones relacionadas