SQL Server - 插入触发器后 - 更新同一表中的另一列
我有这个数据库触发器:
CREATE TRIGGER setDescToUpper
ON part_numbers
AFTER INSERT,UPDATE
AS
DECLARE @PnumPkid int, @PDesc nvarchar(128)
SET @PnumPkid = (SELECT pnum_pkid FROM inserted)
SET @PDesc = (SELECT UPPER(part_description) FROM inserted)
UPDATE part_numbers set part_description_upper = @PDesc WHERE pnum_pkid=@PnumPkid
GO
这是一个坏主意吗?那就是更新同一个表上的列。我希望它在插入和更新时都触发。
它有效,我只是害怕周期性情况。触发器内的更新会一次又一次地触发触发器。 会发生这种情况吗?
请不要对大写字母吹毛求疵。疯狂的情况。
I've got this database trigger:
CREATE TRIGGER setDescToUpper
ON part_numbers
AFTER INSERT,UPDATE
AS
DECLARE @PnumPkid int, @PDesc nvarchar(128)
SET @PnumPkid = (SELECT pnum_pkid FROM inserted)
SET @PDesc = (SELECT UPPER(part_description) FROM inserted)
UPDATE part_numbers set part_description_upper = @PDesc WHERE pnum_pkid=@PnumPkid
GO
Is this a bad idea? That is to update a column on the same table. I want it to fire for both insert and update.
It works, I'm just afraid of a cyclical situation. The update, inside the trigger, fires the trigger, and again and again. Will that happen?
Please, don't nitpick at the upper case thing. Crazy situation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
它取决于数据库上当前设置的触发器的递归级别。
如果你这样做:
或者这样:
上面的触发器将不会再次被调用,并且你将是安全的(除非你陷入某种死锁;这可能是可能的,但也许我错了)。
尽管如此,我不认为这是一个好主意。更好的选择是使用INSTEAD OF 触发器。这样您就可以避免在数据库上执行第一次(手动)更新。只有触发器内定义的才会被执行。
INSTEAD OF INSERT 触发器如下所示:
这将自动用该语句“替换”原始 INSERT 语句,并对
part_description
字段应用显式 UPPER 调用。INSTEAD OF UPDATE 触发器是类似的(我不建议您创建单个触发器,请将它们分开)。
另外,这解决了@Martin评论:它适用于多行插入/更新(您的示例不适用于)。
It depends on the recursion level for triggers currently set on the DB.
If you do this:
Or this:
That trigger above won't be called again, and you would be safe (unless you get into some kind of deadlock; that could be possible but maybe I'm wrong).
Still, I do not think this is a good idea. A better option would be using an INSTEAD OF trigger. That way you would avoid executing the first (manual) update over the DB. Only the one defined inside the trigger would be executed.
An INSTEAD OF INSERT trigger would be like this:
This would automagically "replace" the original INSERT statement by this one, with an explicit UPPER call applied to the
part_description
field.An INSTEAD OF UPDATE trigger would be similar (and I don't advise you to create a single trigger, keep them separated).
Also, this addresses @Martin comment: it works for multirow inserts/updates (your example does not).
另一种选择是将更新语句包含在 IF 语句中,并调用 TRIGGER_NESTLEVEL() 来限制更新正在第二次运行。
当触发器最初运行时,TRIGGER_NESTLEVEL 设置为 1,因此将执行更新语句。该更新语句将依次触发相同的触发器,只不过这次 TRIGGER_NESTLEVEL 设置为 2 并且更新语句将不会被执行。
您还可以首先检查 TRIGGER_NESTLEVEL,如果它大于 1,则调用 RETURN 退出触发器。
Another option would be to enclose the update statement in an IF statement and call TRIGGER_NESTLEVEL() to restrict the update being run a second time.
When the trigger initially runs the TRIGGER_NESTLEVEL is set to 1 so the update statement will be executed. That update statement will in turn fire that same trigger except this time the TRIGGER_NESTLEVEL is set to 2 and the update statement will not be executed.
You could also check the TRIGGER_NESTLEVEL first and if its greater than 1 then call RETURN to exit out of the trigger.
请改用计算列。使用计算列几乎总是比触发器更好的主意。
请参阅下面使用 UPPER 函数的计算列的示例:
这听起来不像是破记录或其他任何东西,但这非常重要。切勿编写在多个记录插入/更新/删除时无法正常工作的触发器。这是一种非常糟糕的做法,因为迟早会发生其中一种情况,并且您的触发器将导致数据完整性问题,因为它不会精确地失败,它只会在其中一条记录上运行该过程。这可能需要很长时间,直到有人发现混乱,并且通常不可能正确修复数据。
Use a computed column instead. It is almost always a better idea to use a computed column than a trigger.
See Example below of a computed column using the UPPER function:
And not to sound like a broken record or anything, but this is critically important. Never write a trigger that will not work correctly on multiple record inserts/updates/deletes. This is an extremely poor practice as sooner or later one of these will happen and your trigger will cause data integrity problems asw it won't fail precisely it will only run the process on one of the records. This can go a long time until someone discovers the mess and by themn it is often impossible to correctly fix the data.
当无事可做时退出触发器可能会更安全。检查嵌套级别或通过关闭 RECURSIVE 来更改数据库可能容易出现问题。
Ms sql 在触发器中提供了一种简单的方法来查看特定列是否已更新。使用 UPDATE() 方法查看某些列是否已更新,例如 UPDATE(part_description_upper)。
It might be safer to exit the trigger when there is nothing to do. Checking the nested level or altering the database by switching off RECURSIVE can be prone to issues.
Ms sql provides a simple way, in a trigger, to see if specific columns have been updated. Use the UPDATE() method to see if certain columns have been updated such as UPDATE(part_description_upper).
是的,它会递归地调用您的触发器,除非您关闭递归触发器设置:
MSDN 在 http://msdn.microsoft.com/en-us/library/aa258254(SQL.80).aspx 位于“递归触发器”标题下。
Yes, it will recursively call your trigger unless you turn the recursive triggers setting off:
MSDN has a good explanation of the behavior at http://msdn.microsoft.com/en-us/library/aa258254(SQL.80).aspx under the Recursive Triggers heading.
是的...有一个额外的步骤来更新表,您可以在其中设置初始插入中的值可能是一个额外的、可以避免的过程。
您是否有权访问原始插入语句,实际上可以使用 UPPER(part_description) 值将part_description 插入到part_description_upper 列中?
经过思考,您可能没有访问权限,因为您可能会这样做,所以也应该提供一些选项...
1)取决于此part_description_upper列的需要,如果只是为了“查看”,那么可以使用返回part_description值和“ToUpper()”它(取决于编程语言)。
2) 如果想避免“实时”处理,只需创建一个 sql 作业,在低流量期间每天检查一次您的值,并将该列更新为当前未设置的任何值的 UPPER part_description 值。
3)跟随你的触发器(并像其他人提到的那样观察递归)......
HTH
Dave
Yea...having an additional step to update a table in which you can set the value in the inital insert is probably an extra, avoidable process.
Do you have access to the original insert statement where you can actually just insert the part_description into the part_description_upper column using UPPER(part_description) value?
After thinking, you probably don't have access as you would have probably done that so should also give some options as well...
1) Depends on the need for this part_description_upper column, if just for "viewing" then can just use the returned part_description value and "ToUpper()" it (depending on programming language).
2) If want to avoid "realtime" processing, can just create a sql job to go through your values once a day during low traffic periods and update that column to the UPPER part_description value for any that are currently not set.
3) go with your trigger (and watch for recursion as others have mentioned)...
HTH
Dave
上面的触发器将在插入之前更新列值。
例如,如果我们将 COLUMNA 的值指定为 null,则每个插入语句都会将该列更新为 null。
The above trigger will update the column value before inserting.
For example if we give the value of COLUMNA as null it will update the column as null for each insert statement.