SQL Server - 插入触发器后 - 更新同一个表中的另一列

Lan*_*rry 24 sql-server triggers sql-server-2008

我有这个数据库触发器:

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
Run Code Online (Sandbox Code Playgroud)

这是一个坏主意吗?那就是更新同一个表上的列.我希望它为插入和更新启动.

它有效,我只是害怕周期性的情况.触发器内的更新会一次又一次地触发触发器.那会发生吗?

请不要挑选大写的东西.疯狂的情况.

rse*_*nna 39

它取决于当前在DB上设置的触发器的递归级别.

如果你这样做:

SP_CONFIGURE 'nested_triggers',0
GO
RECONFIGURE
GO
Run Code Online (Sandbox Code Playgroud)

或这个:

ALTER DATABASE db_name
SET RECURSIVE_TRIGGERS OFF
Run Code Online (Sandbox Code Playgroud)

上面的那个触发器不会被再次调用,你会安全的(除非你遇到某种僵局;这可能是可能的,但也许我错了).

不过,我认为这是一个好主意.更好的选择是使用INSTEAD OF触发器.这样您就可以避免通过DB执行第一次(手动)更新.只执行触发器内定义的那个.

INSTEAD OF INSERT触发器将是这样的:

CREATE TRIGGER setDescToUpper ON part_numbers
INSTEAD OF INSERT
AS
BEGIN
    INSERT INTO part_numbers (
        colA,
        colB,
        part_description
    ) SELECT
        colA,
        colB,
        UPPER(part_description)
    ) FROM
        INSERTED
END
GO
Run Code Online (Sandbox Code Playgroud)

这将自动"替换"原始INSERT语句,并将明确的UPPER调用应用于该part_description字段.

INSTEAD OF UPDATE触发器将类似(我建议您不要创建单个触发器,将它们分开).

此外,这解决了@Martin评论:它适用于多行插入/更新(您的示例没有).


Jor*_*iss 15

另一种选择是将更新语句包含在IF语句中,并调用TRIGGER_NESTLEVEL()来限制第二次运行更新.

CREATE TRIGGER Table_A_Update ON Table_A AFTER UPDATE 
AS
IF ((SELECT TRIGGER_NESTLEVEL()) < 2)
BEGIN
    UPDATE a
    SET Date_Column = GETDATE()
    FROM Table_A a
    JOIN inserted i ON a.ID = i.ID
END
Run Code Online (Sandbox Code Playgroud)

当触发器最初运行时,TRIGGER_NESTLEVEL设置为1,因此将执行更新语句.该更新语句将依次触发相同的触发器,除非此时TRIGGER_NESTLEVEL设置为2并且不会执行update语句.

您还可以先检查TRIGGER_NESTLEVEL,如果它大于1,则调用RETURN退出触发器.

IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
Run Code Online (Sandbox Code Playgroud)

  • 请务必注意,如果事件是由另一个触发器生成的,则此触发器将不会运行.例如,如果表A被更新并且触发器更新表B我们有`IF((SELECT TRIGGER_NESTLEVEL())> 1)RETURN;`那么表B上的触发器将返回,因为嵌套级别太大. (2认同)

HLG*_*GEM 6

请改用计算列.使用计算列而不是触发器几乎总是更好的主意.

使用UPPER函数查看计算列的下面示例:

create table #temp (test varchar (10), test2 AS upper(test))
insert #temp (test)
values ('test')
select * from #temp
Run Code Online (Sandbox Code Playgroud)

而不是听起来像破纪录或任何东西,但这是至关重要的.切勿编写在多个记录插入/更新/删除时无法正常工作的触发器.这是一种非常糟糕的做法,因为迟早会发生其中一种情况,并且您的触发器将导致数据完整性问题,因为它不会精确地失败,它只会在其中一条记录上运行该进程.这可能需要很长时间,直到有人发现混乱,并且通过它们通常无法正确修复数据.