Mengapa tidak menggunakan INSTEAD OF
pemicu? Ini membutuhkan sedikit lebih banyak pekerjaan (yaitu UPDATE
berulang-ulang pernyataan) tetapi setiap kali Anda dapat mencegah pekerjaan, alih-alih membiarkannya terjadi dan kemudian memutarnya kembali, Anda akan menjadi lebih baik.
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
Ini tidak cocok. Kriteria yang saya tinggalkan diabaikan karena suatu alasan:dapat menjadi rumit untuk menentukan apakah nilai kolom telah berubah, karena bergantung pada tipe data, apakah kolom dapat berupa NULL, dll. AFAIK fungsi pemicu bawaan hanya dapat mengetahui apakah kolom tertentu telah ditentukan, bukan apakah nilainya benar-benar berubah dari sebelumnya.
EDIT mengingat Anda hanya peduli dengan kolom lain yang diperbarui karena pemicu setelahnya, saya pikir INSTEAD OF
berikut pemicu dapat menggantikan kedua pemicu yang ada dan juga menangani beberapa baris yang diperbarui sekaligus (beberapa tanpa memenuhi kriteria Anda):
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