Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como evitar atualizações em uma tabela, com exceção de uma situação


Por que não usar um INSTEAD OF acionar? Requer um pouco mais de trabalho (ou seja, um UPDATE repetido declaração), mas sempre que você puder impedir o trabalho, em vez de deixá-lo acontecer e depois revertê-lo, você ficará melhor.
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

Isso não se encaixa perfeitamente. Os critérios que deixei de fora são deixados de fora por um motivo:pode ser complexo determinar se um valor de coluna foi alterado, pois depende do tipo de dados, se a coluna pode ser NULL, etc. AFAIK as funções de gatilho internas só pode dizer se uma determinada coluna foi especificada, não se o valor realmente mudou de antes.

EDITAR considerando que você está preocupado apenas com as outras colunas que são atualizadas devido ao acionador after, acho que o seguinte INSTEAD OF O gatilho pode substituir os dois gatilhos existentes e também lidar com várias linhas atualizadas de uma só vez (algumas sem atender aos seus critérios):
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