Sql server 在更新触发器触发之前和之后检查约束冲突
我有一个表,它有一个Sql server 在更新触发器触发之前和之后检查约束冲突,sql-server,sql-server-2008,tsql,check-constraints,database-trigger,Sql Server,Sql Server 2008,Tsql,Check Constraints,Database Trigger,我有一个表,它有一个bit列和一个相应的datetime2列,跟踪设置该标志的时间: CREATE TABLE MyTable ( Id int primary key identity, Processed bit not null, DateTimeProcessed datetime2 ) 我添加了一个检查约束,如下所示: ALTER TABLE MyTable ADD CHECK ((Processed = 0 AND DateTimeProcessed
bit
列和一个相应的datetime2
列,跟踪设置该标志的时间:
CREATE TABLE MyTable
(
Id int primary key identity,
Processed bit not null,
DateTimeProcessed datetime2
)
我添加了一个检查约束,如下所示:
ALTER TABLE MyTable
ADD CHECK ((Processed = 0 AND DateTimeProcessed IS NULL)
OR (Processed = 1 AND DateTimeProcessed IS NOT NULL))
我试图使用更新后的触发器控制DateTimeProcessed
列的设置:
CREATE TRIGGER tr_MyTable_AfterUpdate ON MyTable
AFTER UPDATE
AS
BEGIN
IF(UPDATE(Processed))
BEGIN
UPDATE MyTable
SET DateTimeProcessed = CASE
WHEN tab.Processed = 1 THEN GETDATE()
ELSE NULL
END
FROM MyTable tab
JOIN INSERTED ins
ON ins.Id = tab.Id
END
END
问题在于,check约束是在AFTER UPDATE
触发器运行之前强制执行的,因此更新Processed
列时违反了该约束
实现我在这里尝试的目标的最佳方式是什么?现在,根据MSDN页面:
如果表具有外键或CHECK约束和触发器,则在执行触发器之前会计算约束条件
这也排除了使用“代替”触发器的可能性
您应该删除CHECK约束,因为最终不需要它,因为AFTER触发器本身可以提供相同的规则强制:
- 您已经在确保位字段设置为1时设置了日期字段
- 您的CASE语句已在通过清空日期字段来处理设置为0的位字段
- 如果更新(DateTimeProcessed)
,您可以使用另一个块来检查,然后将其恢复到已删除的表中的状态,或者抛出一个错误
- 如果将其更新回原始值,则可能需要测试递归触发器调用,如果是递归调用,则退出
- 如果您想抛出错误,只需使用以下内容:
IF(UPDATE(DateTimeProcessed))
BEGIN
RAISERROR('Update of [DateTimeProcessed] field is not allowed.', 16, 1);
ROLLBACK; -- cancel the UPDATE statement
RETURN;
END;
请记住,UPDATE()
函数只指示字段在UPDATE语句中;这不是值变化的指示。因此,在执行更新时,SET DateTimeProcessed=DateTimeProcessed
显然不会更改该值,但会导致UPDATE(DateTimeProcessed)
返回“true”
- 您还可以使用列级别在触发器之外处理“规则”的这一部分:
拒绝向{User和/或Role}更新MyTable(DateTimeProcessed)代码>
“建议使用“BEFORE”触发器的评论可能已被删除,因为SQL Server没有“BEFORE”触发器……是的,这可能就是原因,不是吗:)谢谢您的回答。如果直接更新了DateTimeProcessed
,则抛出一个错误似乎是此处要添加的最后一项。@grin0048:是的,我曾建议在该场景中抛出一个错误,这是您所指的还是您没有看到我的更新?不管怎样,我再次更新以重新排列项目符号的顺序,并添加了一些细节,例如处理错误和取消的代码,以及一个新的(鲜为人知的)不涉及代码的选项。是的,我是指你的建议——只是记下我觉得哪一个最有用。再次感谢!