Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server-插入表_Sql_Sql Server_Database_Triggers_Relational Database - Fatal编程技术网

SQL Server-插入表

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

我正在使用以下触发器检查插入/删除表的输出,如何在验证列之后将截获的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

为了检索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
    ;