SQL服务器 - inserted表(SQL Server - Inserted Table)

2019-10-18 00:18发布

我检查使用以下触发插入/删除表的输出,我怎么能通上截获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 UPDATE
AS
    --COMMIT UPDATE THAT WAS INTERCEPTED
END

Answer 1:

你“被截获的UPDATE命令传递到服务器验证列之后”的唯一方法是通过执行UPDATE自己。

选项1 - ROLLBACK

但是,你现在说你不希望有当这些列添加到表列或多列添加到扳机。 所以,你必须简单地回滚任何变化是无效的替代选项。 这可能是这个样子:

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;

选项2 - 在触发执行更新

但是,如果您需要在哪些更新实际上需要更多的控制,如需要在提交之前修改的值,你就必须自己执行更新。 例如:

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
;

这是一个简单的例子,它没有做任何检查,但你的想法-当您执行的更新Sample表,你会看到该值获得额外的+字符-您的更新被拦截和Inserted值(代表更新后所提出的变化)被提交之前被修改。

看到SQL小提琴演示的这个动作。

要留意的唯一的事情就是递归:

  1. 直接递归

    当您的更新可能会导致其他触发器来运行修改同一基表 - 那么你可以让他们之间的乒乓,直到达到最大巢水平,整个事务回滚。 所以,要小心触发之间可能的乒乓效应。

  2. 间接递归

    你可能不担心这个,因为数据库级别的RECURSIVE TRIGGERS选项默认是关闭的SQL Server中。 然而,如果是,你可以得到一个基于新的更新相同的触发射击。

这些通过,进行各种改善:

  • 检查TRIGGER_NESTLEVEL触发器内,并退出触发如果已经嵌套的深度不够。

  • 为了避免直接递归只,结合触发器。

  • 在某些特定情况下战略性分配,其触发将首先/最后的运行可能会解决问题。 您不能指定绝对的先后顺序,但你可以选择的第一个和最后一个。

需要注意的是乒乓问题适用于任何类型的触发器, INSTEAD OFAFTER ,即修改自己的基表,或通过另一台参与更新的链(即有修改另一个表的触发器...)最终回来修改基表。

选项2B - 预处理AFTER UPDATE触发器。

我把这个选项2B,因为它确实是选项2,但增强。 如果你不希望每次都手动更新触发你列添加到表(情绪我完全同意),你可以自动完成这个。 创建可以创建注意到,你所需要的所有验证适当的触发因素的存储过程。 你可以把基础代码此验证到一个表,然后在SP选入变量,添加在SQL脚本通过在挖掘信息更新的最后更新列INFORMATION_SCHEMA.COLUMNS视图,然后终于改写了扳机。 这可能进一步被连接到一个DDL触发器,因此,这是100%的自动化:你想添加或删除基表中的列,DDL触发器就会触发,并改写DML触发器为您服务。

这听起来像一个大量的工作,但如果你把它设计成为数据驱动它可以推广在整个数据库的任何表,这可能是很有价值的,这取决于您的使用情景工作。



Answer 2:

为了找回UPDATE语句使用SQLprofiler。 插入的表格是被插入或更新的快照(这里存储的新值)。 删除的表是什么都在你正在更新/删除值快照。 你触发将只执行,而不是对表Test1的更新中的命令,你可以看到你在插入更新。

勾选此文章有关触发器。



Answer 3:

嗯,这是一个选项...

/*
        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

这将创建一个DateTime记录表。 更新试图更新其为“现在”,但它是一个事务中运行并转储它插入并删除记录到一个临时表的工作。 更新后,你可以做你想做对表中的数据,以确定是否要提交或回滚更改任何检查。 我有这样写到总是回滚作为一个例子。



文章来源: SQL Server - Inserted Table