2010-02-10 155 views
2

我在SQL Server 2008中有一个更新触发器。如果某些列已被修改,我只需要执行触发器操作。因此,我想检查一下发生了什么变化。TSQL更新触发器:加入插入和删除

T-SQL提供了“if update(columnName)”构造。但是,如果许多行已经更新,其中只有一个单一的一个改变了特定的列值“如果更新()”将不得不返回true。这将使我执行触发器操作的行数远多于所需的行数。

因此,不是使用“if update()”,我认为我只需加入虚拟删除和插入表(更新前后的行)并自己比较相关列。但是,我怎样才能加入这两张桌子呢?我无法使用表的主键,因为这可能是由更新修改的。我唯一能想到的就是通过row_number()进行连接,即隐式表格排序。这种感觉非常错误的,虽然我不知道SQL Server是否确实提供了在插入的行命令一样删除任何guarantuees。

+6

永远不会改变主键。如果您需要更改主键的值,那么您应该使用代理主键,如身份。 – 2010-02-10 13:49:45

+0

为什么外键约束允许“更新级联/设置为空”如果“永不改变主键”就是这样一个铁律?如果主键由在现实世界中有意义的东西组成,它可能会在某个时刻发生改变。我尽量避免它在可能的情况下,我自己的模式具有不可变的主键,但我不认为它是一个绝对的禁忌?在这种特殊情况下,模式设计不在我的控制之下,所以我对此无能为力。 – BuschnicK 2010-02-10 14:26:28

+0

外键可能指的是唯一的约束,不仅对PK。这可以在一个非常简单的系统中使你的参数aobut CASCADE – 2010-02-10 15:01:41

回答

3

随着您的设计(允许更改主键),构建一致的逻辑似乎非常困难。

说,你有这样的表:

id value 
1 2 
2 1 

并执行这个操作:

UPDATE mytable 
SET  id = CASE WHEN id = 1 THEN 2 ELSE 1 END, 
     value = CASE WHEN value = 1 THEN 2 ELSE 1 END 

会同时更新记录,但离开桌子,因为这:

id value 
2 1 
1 2 

,这从关系的角度来看类似于根本不改变表格。

主键的整点在于它们从不改变。

+0

同意。但是,你如何禁止修改主键?一般来说? 因为桌子的设计不在我的控制之下,所以在任何情况下它都不会成为我的选择。看到我的评论devio的答案。 – BuschnicK 2010-02-10 13:51:20

+0

@BuschnicK:使用'IF UPDATE()',如你的问题:) – Quassnoi 2010-02-10 13:54:45

0

如果使用IDENTITY列作为主键,则不存在更新PK列的问题。

+0

主键由多个列组成。我喜欢避免身份密钥(参见Joe Celko对此的一些论点)。无论如何,表架构不受我控制。这就是触发器的要点 - 将原始表的更改传播给我们自己。 – BuschnicK 2010-02-10 13:49:42

+0

所以你可以修改你不控制的表上的触发器,但不能修改模式本身?你可能可以用不可变的主键构造一个新表,并在它的原始表中公开一个正确命名的视图吗?这将允许您拥有可以在触发器中跟踪的固定ID。 – mwigdahl 2010-02-10 20:19:14

+0

这些表格住在我的数据库服务器上,我是管理员,所以从这个意义上说,我可以随心所欲地做任何事情。但是,他们“属于”商业ERP系统,如果我显着改变表格布局或行为,就会中断ERP系统。 – BuschnicK 2010-02-11 10:05:22

0

防止PK更改,添加到您的触发器的顶部:

IF (UPDATE(yourPKcol1) OR UPDATE(yourPKcol2)) 
BEGIN 
    RAISERROR('Primary Key change not permitted!',16,1) 
    ROLLBACK 
    RETURN 
END 
0

你最好的选择可能是(因为我在评论中提到以上)创建一个新表,如果可能的话,这包括在最初的所有数据,而且还包括一个不变的主键(IDENTITY工作,或者如果你喜欢,你可以用别的东西)。然后,您可以公开这个模仿原始表的名称和模式的新表的视图。这会给你一个固定的ID,你可以用它来跟踪你想要的改变。

所有这一切都假设一个视图在你的特定情况下能够正常工作 - 如果应用程序做了一些非常奇怪的事情,它可能无法正常工作,但是如果它只是抛出标准的CRUD风格的SQL,它应该可以正常工作。

0

你的代价是简单&可维护性VS性能 如果性能是不是优先使用,如果更新(YourTriggerActionColumn)直接 如果性能是优先考虑那么做的方式是用“如果更新(PrimaryKeyColumn)”因此,如果主键没有改变使用插入,删除,加入否则,如果主键没有改变,然后选中“如果更新(YourTriggerActionColumn)” 以来的PK不经常然后更改大部分的插入,删除的时间join方法将因此用于解决您的性能问题。 稍迟,但只是我的2美分:)