Sql server SQL Server-插入触发器后-更新同一表中的另一列
我有一个数据库触发器:Sql server SQL Server-插入触发器后-更新同一表中的另一列,sql-server,sql-server-2008,triggers,Sql Server,Sql Server 2008,Triggers,我有一个数据库触发器: 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_n
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
这是个坏主意吗?即更新同一表中的列。我希望它能同时启动插入和更新
它是有效的,我只是害怕周期性的情况。触发器内部的更新会一次又一次地触发触发器这会发生吗?
请不要挑剔大写字母。疯狂的情况。这取决于数据库上当前设置的触发器的递归级别 如果您这样做:
SP_CONFIGURE 'nested_triggers',0
GO
RECONFIGURE
GO
或者这个:
ALTER DATABASE db_name
SET RECURSIVE_TRIGGERS OFF
上面的触发器不会被再次调用,您将是安全的(除非您陷入某种僵局;这是可能的,但可能我错了)
不过,我认为这不是一个好主意。更好的选择是使用。这样可以避免在数据库上执行第一次(手动)更新。只有在触发器中定义的一个将被执行
INSERT而非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
这将自动地用这个INSERT语句“替换”原始INSERT语句,并对part\u description
字段应用显式的上限调用
一个代替更新的触发器将是类似的(我不建议您创建一个触发器,将它们分开)
此外,这还涉及@Martin comment:它适用于多行插入/更新(您的示例不适用)。是的……有一个额外的步骤来更新表,您可以在其中设置初始插入中的值,这可能是一个额外的、可避免的过程。 您是否可以访问原始insert语句,在该语句中,您实际上可以使用upper(part_description)值将part_描述插入part_description_上一栏 经过思考,你可能没有访问权限,因为你可能已经这样做了,所以也应该给出一些选择 1) 取决于此part_description_上栏的需要,如果只是为了“查看”,则可以只使用返回的part_description值和“ToUpper()”值(取决于编程语言) 2) 如果想要避免“实时”处理,可以创建一个sql作业,在低流量期间每天检查一次您的值,并将该列更新为当前未设置的任何值的上半部分描述值 3) 使用触发器(注意其他人提到的递归) 嗯
Dave是的,它将递归调用您的触发器,除非您关闭递归触发器设置:
ALTER DATABASE db_name SET RECURSIVE_TRIGGERS OFF
MSDN对递归触发器标题下的行为有很好的解释。使用计算列。使用计算列几乎总是比使用触发器更好的主意 请参见下面使用UPPER函数的计算列示例:
create table #temp (test varchar (10), test2 AS upper(test))
insert #temp (test)
values ('test')
select * from #temp
不要听起来像一张破唱片或其他什么,但这是至关重要的。切勿编写无法在多个记录插入/更新/删除上正常工作的触发器。这是一种非常糟糕的做法,因为迟早会发生其中一种情况,您的触发器将导致数据完整性问题,因为它不会完全失败,它只会在其中一条记录上运行该过程。这可能会持续很长一段时间,直到有人发现乱七八糟的情况,而且往往无法正确修复数据 另一个选项是将update语句包含在IF语句中,并调用以限制第二次运行更新
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
上述触发器将在插入前更新列值。
例如,如果我们将COLUMNA的值设为null,那么对于每个insert语句,它都会将列更新为null。在无事可做时退出触发器可能更安全。检查嵌套级别或通过关闭递归更改数据库可能容易出现问题 Ms sql在触发器中提供了一种查看特定列是否已更新的简单方法。使用UPDATE()方法查看某些列是否已更新,例如UPDATE(part_description_upper)
多行插入/更新的触发器将失败。但是如果您仍然需要存储,为什么
part\u description\u upper
不是一个持久化的计算列呢?(我假设pnum\u pkid
是part\u number
?)的主键@marc\u s不会出现错误无法更新part\u number。。。因为调用此触发器的语句已经使用了它
,所以计算列是一个很好的选择。但你也应该补充一点,为了避免选择缓慢,我们也可以i)和ii)。是的,但仍然。。。自己编写一个小测试,比较一个常规列和一个持久化计算列(都有索引),然后选择常规列……非常感谢。出于安全原因,在许多启用web的SQL数据库上不允许使用SP_CONFIGURE。请务必注意,如果事件由另一个触发器生成,则此触发器将不会运行。例如,如果更新了表A,并且触发器更新了表B,其中我们有if((SELECT Trigger_NESTLEVEL())>1)返回代码>然后表B上的触发器将返回,因为嵌套级别太大。作为一个(imho)好习惯,我总是从触发器中发出一个带有触发器名称的print语句。。。只是为了在从分析器运行查询时给出指示,这会处理目标表中的自动递增列吗?@BlackKnight:当然,像往常一样:只是不要引用INSERT
语句中的任何IDENTITY
列。@tEsTA让我解释得更清楚一些。假设我想基于标识列设置另一列。我想此时不会设置标识列。我还可以使用这种技术吗?还是我需要一个后插入?@BlackKnight希望我不会太晚(1年不算太多:P)。但我同意在这种情况下,在插入后使用触发器更容易。为了使用而不是INSERT
,您必须在触发器中使用两条语句:一条
IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
create or replace
TRIGGER triggername BEFORE INSERT ON
table FOR EACH ROW
BEGIN
/*
Write any select condition if you want to get the data from other tables
*/
:NEW.COLUMNA:= UPPER(COLUMNA);
--:NEW.COUMNa:= NULL;
END;
IF UPDATE(part_description_upper)
return