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