sql >> Base de Datos >  >> RDS >> Sqlserver

Cómo evitar actualizaciones en una tabla, con una excepción en una situación

¿Por qué no usar un INSTEAD OF? ¿generar? Requiere un poco más de trabajo (es decir, un UPDATE repetido declaración) pero en cualquier momento que pueda evitar el trabajo, en lugar de dejar que suceda y luego revertirlo, estará mejor.

CREATE TRIGGER [dbo].[Item_BeforeUpdate_AnyBilled]
ON [dbo].[Item]
INSTEAD OF UPDATE
AS 
BEGIN
  SET NOCOUNT ON;

  IF EXISTS 
  (
     SELECT 1 FROM inserted i
       JOIN deleted AS d ON i.ItemId = d.ItemId
       WHERE d.BillId IS NULL -- it was NULL before, may not be NULL now
  )
  BEGIN
     UPDATE src 
       SET col1 = i.col1 --, ... other columns
          ModifiedDate = CURRENT_TIMESTAMP -- this eliminates need for other trigger
       FROM dbo.Item AS src
       INNER JOIN inserted AS i
       ON i.ItemId = src.ItemId
       AND (criteria to determine if at least one column has changed);
  END
  ELSE
  BEGIN
     RAISERROR(...);
  END
END
GO

Esto no encaja perfectamente. Los criterios que he omitido se omiten por una razón:puede ser complejo determinar si el valor de una columna ha cambiado, ya que depende del tipo de datos, si la columna puede ser NULL, etc. AFAIK, las funciones de activación integradas solo puede decir si se especificó una determinada columna, no si el valor realmente cambió desde antes.

EDITAR teniendo en cuenta que solo le preocupan las otras columnas que se actualizan debido al desencadenante posterior, creo que lo siguiente INSTEAD OF el activador puede reemplazar a sus dos activadores existentes y también tratar con varias filas actualizadas a la vez (algunas sin cumplir con sus criterios):

CREATE TRIGGER [dbo].[Item_BeforeUpdate_AnyBilled]
ON [dbo].[Item]
INSTEAD OF UPDATE
AS 
BEGIN
  SET NOCOUNT ON;

  UPDATE src SET col1 = i.col1 --, ... other columns,
     ModifiedDate = CURRENT_TIMESTAMP
     FROM dbo.Item AS src
     INNER JOIN inserted AS i
     ON src.ItemID = i.ItemID
     INNER JOIN deleted AS d
     ON i.ItemID = d.ItemID 
     WHERE d.BillID IS NULL; 

  IF @@ROWCOUNT = 0
  BEGIN
    RAISERROR(...);
  END
END
GO