SQL Server-插入表
我正在使用以下触发器检查插入/删除表的输出,如何在验证列之后将截获的UPDATE命令传递给服务器SQL Server-插入表,sql,sql-server,database,triggers,relational-database,Sql,Sql Server,Database,Triggers,Relational Database,我正在使用以下触发器检查插入/删除表的输出,如何在验证列之后将截获的UPDATE命令传递给服务器 CREATE TRIGGER Test1_LastUpdate ON Test1 INSTEAD OF UPDATE AS SELECT * FROM Inserted SELECT * FROM Deleted GO 编辑:我正在寻找一个在模式更新后不需要更改的解决方案 CREATE TRIGGER Test1_LastUpdate2 ON Test1 INSTEAD OF U
CREATE TRIGGER Test1_LastUpdate ON Test1
INSTEAD OF UPDATE
AS
SELECT * FROM Inserted
SELECT * FROM Deleted
GO
编辑:我正在寻找一个在模式更新后不需要更改的解决方案
CREATE TRIGGER Test1_LastUpdate2 ON Test1
INSTEAD OF UPDATE
AS
--COMMIT UPDATE THAT WAS INTERCEPTED
END
为了检索UPDATE语句,请使用SQLprofiler。插入表是插入或更新内容的快照(此处存储了新值)。删除的表是您正在更新/删除的表中的值的快照。您将只对表Test1执行触发器而不是更新命令,并且您可以在插入的表中看到您正在更新的内容
关于触发器,请检查此选项。这是一个选项
/*
Create Table ExampleTable (LastRefreshed DateTime)
Go
Insert ExampleTable
Select GetDate()
*/
Begin Tran
If Object_ID('tempdb..#check') Is Not Null Drop Table #check
Create Table #check (InsertedVal DateTime, DeletedVal DateTime)
Update ExampleTable
Set LastRefreshed = GetDate()
Output Inserted.LastRefreshed As InsertedVal, Deleted.LastRefreshed As DeletedVal Into #check
Select *
From #check
If Exists (Select 1
From #check
Where InsertedVal > DeletedVal)
Begin
Rollback Tran
End
Else
Begin
Commit Tran
End
这将创建一个带有日期时间记录的表。更新尝试将其更新为“现在”,但它在事务中运行,并将插入和删除的记录转储到临时表中以进行处理。更新后,您可以根据表数据执行任何检查,以确定是提交还是回滚更改。我写这篇文章的目的是为了始终回滚,例如。您“在验证列后将截获的更新命令传递给服务器”的唯一方法是自己执行更新
选项1-回滚
但是,您现在已经说过,当这些列添加到表中时,您不希望必须向触发器添加更多的列。因此,您可以选择简单地回滚任何无效的更改。可能看起来像这样:
CREATE TRIGGER TR_Sample_U ON dbo.Sample -- No AFTER trigger needed here!
AS
IF EXISTS ( --check for disallowed modifications
SELECT *
FROM
Inserted I
INNER JOIN Deleted D
ON I.SampleID = D.SampleID
WHERE
I.Something <> D.Something
AND I.UpdateDate = D.UpdateDate
)
ROLLBACK TRAN;
这是一个不做任何检查的简单示例,但是您得到了一个想法——当您在示例
表上执行更新时,您将看到该值获取了一个额外的+
字符——您的更新被截获,并且插入了值(表示更新后建议的更改)在提交之前已修改
这一点正在发挥作用
唯一需要注意的是递归:
直接递归
当更新可能导致其他触发器运行修改相同的基表时——然后您可以在它们之间进行乒乓球,直到达到最大嵌套级别,并回滚整个事务。因此,请注意触发器之间可能存在的乒乓
间接递归
您可能不必担心这个问题,因为SQL Server中的默认设置是关闭的。但是,如果它处于启用状态,则可以根据新的更新获得相同的触发器触发
这些问题可以通过以下方式得到改善:
- 检查触发器内部的
TRIGGER\u NESTLEVEL
,如果已经嵌套足够深,则退出触发器
- 为了避免直接递归,请组合触发器
- 在某些特定情况下,策略性地分配哪个触发器将首先/最后运行可以解决问题。不能指定绝对顺序,但可以选择第一个和最后一个
请注意,乒乓问题适用于任何类型的触发器,而不是
或
之后的
,它们修改自己的基表,或者通过另一个表(具有修改另一个表的触发器…)参与更新链,最终返回修改基表
选项2B-预处理更新后触发器。
我把这个选项称为2B,因为它实际上是选项2,但有一个增强。如果您不想在每次向表中添加列时都手动更新触发器(我完全同意这种看法),您可以自动执行此操作。创建一个存储过程,该存储过程可以创建一个适当的触发器来观察您需要的所有验证。您可以将此验证的基本代码放入一个表中,然后在SP中将其选择为变量,添加SQL脚本,通过在information\u SCHEMA.columns
视图中挖掘信息来更新列,最后重写触发器。这还可以附加到DDL触发器,这样它就100%自动化了:您可以从基表中添加或删除一列,DDL触发器将触发,然后为您重写DML触发器
这听起来需要做很多工作,但如果您将其设计为数据驱动,则可以将其推广到处理整个数据库中的任何表,这可能非常有价值,具体取决于您的使用场景。什么意思是它与提交给表的内容不匹配?通过截取
更新
,您正在阻止它提交到表中,但是如果您没有截取它,插入的记录应该是表中要更新的记录。听起来你想为UPDATE设置一个触发器@Love2Learn我知道我正在拦截UPDATE命令。我正在寻找一种在数据进入数据库之前检查数据的方法。我想要的是检查插入/删除的表,然后根据特定条件提交发送到服务器的操作。我会把代码编辑得更清楚。不,你不会得到一个无休止的触发循环。这是完全错误的信息。你唯一需要担心的触发器是其他触发器,而不是正在运行的触发器。谢谢@ErikE。。。我从别人那里听到过这个,从来没有费心去查或确认。我消除了错误信息。这个选项仍然有效,但我确实希望避免虚假信息长期存在。我会查一查,然后自学。谢谢请看。请注意,您可以在两个触发器之间获得“乒乓球”,但不能在一个触发器之间获得。解决方法是检查触发器\u NESTLEVEL
,如果触发器已在正确的嵌套级别运行,则不执行任何更新。@ErikE此错误信息似乎比我从某人那里听到的更广泛。。。我测试了它,它确实是完全错误的。再次感谢!对不起,我
CREATE TRIGGER TR_Sample_U ON dbo.Sample
INSTEAD OF UPDATE
AS
SET NOCOUNT ON;
SET XACT_ABORT ON;
UPDATE S
SET S.Value = I.Value + '+'
FROM
dbo.Sample S
INNER JOIN Inserted I
ON S.SampleID = I.SampleID
;