【发布时间】:2012-02-29 21:36:21
【问题描述】:
我有一个表,其中包含可以成为账单一部分的记录。我可以分辨出哪些已经是账单的一部分,因为该表有一个 BillId 列,当发生这种情况时,应用程序代码会更新该列。我想阻止更新具有非空 BillId 的任何记录。我认为以下应该解决这个问题:
CREATE TRIGGER [Item_Update_AnyBilled]
ON [dbo].[Item]
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @AnyBilled BIT;
SELECT TOP(1) @AnyBilled = 1
FROM inserted i
JOIN deleted d ON i.ItemId = d.ItemId
WHERE d.BillId IS NOT NULL;
IF COALESCE(@AnyBilled, 0) = 1 BEGIN
RAISERROR(2870486, 16, 1); -- Cannot update a record that is part of a bill.
ROLLBACK TRANSACTION;
END;
END;
但是,还有一个问题。 Item 表还有一个 DATETIME Modified 列,以及一个更新它的触发器。
CREATE TRIGGER [dbo].Item_Update_Modified
ON [dbo].[Item]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE a
SET Modified = getdate()
FROM Item a JOIN inserted i ON i.ItemId = a.ItemId
END
使用这些触发器,将项目添加到账单总是会导致 RAISERROR 触发。大概是因为当 BillId 被填充时,Item_Update_AnyBilled 允许它通过,因为 deleted.BillId 为 NULL,但 Item_Update_Modified 然后被执行,并且该次要更改导致 Item_Update_AnyBilled 再次被执行,而这一次 deleted.BillId 不再为 NULL。
我如何防止更新 Item 表,除非是在 BillId 被填充或唯一更改是 Modified 列的情况下?
我更喜欢不需要我比较每列的插入和删除值(或使用 COLUMNS_UPDATED())的解决方案,因为这会产生维护问题(有人必须记住更新触发器向表中添加或删除新列的时间)。我使用的是 SQL Server 2005。
【问题讨论】:
标签: sql-server sql-server-2005 triggers