Perché non usare un INSTEAD OF
grilletto? Richiede un po' più di lavoro (vale a dire un UPDATE
ripetuto dichiarazione) ma ogni volta che puoi impedire il lavoro, invece di lasciare che accada e poi annullarlo, starai meglio.
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
Questo non si adatta perfettamente. I criteri che ho omesso sono stati omessi per un motivo:può essere complesso determinare se il valore di una colonna è cambiato, poiché dipende dal tipo di dati, se la colonna può essere NULL, ecc. AFAIK le funzioni di trigger integrate può dire solo se è stata specificata una determinata colonna, non se il valore è effettivamente cambiato rispetto a prima.
MODIFICA considerando che sei preoccupato solo per le altre colonne che vengono aggiornate a causa dell'attivazione successiva, penso che il seguente INSTEAD OF
trigger può sostituire entrambi i trigger esistenti e anche gestire più righe aggiornate contemporaneamente (alcune senza soddisfare i tuoi criteri):
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