SQL Server触发器 - 在更新之前复制行

时间:2009-07-27 11:42:54

标签: sql-server triggers

我想在更新之前复制一个表的行,我试图这样做:

CREATE TRIGGER first_trigger_test
on Triggertest
FOR UPDATE
AS
insert into Triggertest select * from Inserted

不幸的是,我收到了错误消息

Msg 8101, Level 16, State 1, Procedure first_trigger_test, Line 6
An explicit value for the identity column in table 'Triggertest' can only be specified when a column list is used and IDENTITY_INSERT is ON.

我认为这是因为id-column;我不能做'除'id之类的事情吗?我不想列出触发器中的所有列,因为它应该尽可能动态......

3 个答案:

答案 0 :(得分:3)

基本上,你不能。您要么必须指定列,要么使用单独的表:

CREATE TRIGGER first_trigger_test
on Triggertest
FOR UPDATE
AS
insert into Triggertest_audit select * from deleted

(其中Triggertest_audit是第二个看起来像Triggertest的表,但是没有主键/标识/等 - 每个逻辑源行通常有多行;不是我认为你实际上想要复制值,而不是新值

答案 1 :(得分:1)

问题发生的原因是您尝试在Triggertest中设置标识列。 这是你的计划吗?

  1. 如果要将新标识列从INSERTED复制到Triggertest,请在没有IDENTITY的情况下在Triggertest中定义列

  2. 如果Triggertest拥有自己的IDENTITY列,请使用:

    插入Triggertest(col1,col2,col3)选择插入的col1,col2,col3

  3. 评论后:

    不,没有动态SQL就无法检测到哪个表并找到所有非标识列。

    但是,如果您添加或删除列,则触发器表和Triggertest之间会出现不匹配,您将收到不同的错误。

    如果你真的希望它是动态的,你必须将所有列连成一个或使用XML来忽略模式。

    最后:

    所有表的列数和数据类型以及可触发性与TriggerTest完全相同...因为这是假设...

答案 2 :(得分:0)

如果您希望每次触发器运行时都构建表,那么您别无选择,只能使用系统表查找列并创建包含这些列定义的表。当然,你的第一步必须是删除现有的表,否则第二次有人更新记录时触发器将无法工作。

但是,我认为你需要重新考虑这个过程。每次更改记录时删除一个表然后创建一个新表是一个非常糟糕的主意。无论如何,当这张桌子每隔一秒左右被消灭并重建时,它是如何有用的?

您可能会考虑做的是创建一个动态过程来创建创建触发器脚本,该脚本具有该表的正确信息但不是动态的。然后,每次进行表更改时,您的配置人员都需要运行此过程。

请记住,触发器执行两项操作至关重要,尽可能快地运行并考虑在批处理中处理所有记录(触发器应该永远不会逐行处理或其他缓慢处理或假设只有一行将在插入或删除的表中)触发器中的动态SQL可能也是一个坏主意,因为您无法预先测试所有可能性,并且当发生意外情况时可能会使整个生产服务器停止尖叫。