Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server-插入触发器后-更新同一表中的另一列_Sql Server_Sql Server 2008_Triggers - Fatal编程技术网

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