Sql server 即使在单行更新时,触发器也会更新整个表

Sql server 即使在单行更新时,触发器也会更新整个表,sql-server,triggers,Sql Server,Triggers,以下触发器用于在位置表中更新行时自动更新。更改可以一次发生一行,也可以一次发生1-n行。但是,当更新单行时,在启用“locations_geteditdate”的同时,将向locations表中的所有28K行写入一个新的时间戳。我知道我错过了一些明显的东西,谢谢你的帮助 ALTER TRIGGER [dbo].[locations_geteditdate] ON [dbo].[TBL_LOCATIONS] instead of update AS begin declare @rec

以下触发器用于在位置表中更新行时自动更新。更改可以一次发生一行,也可以一次发生1-n行。但是,当更新单行时,在启用“locations_geteditdate”的同时,将向locations表中的所有28K行写入一个新的时间戳。我知道我错过了一些明显的东西,谢谢你的帮助

ALTER TRIGGER   [dbo].[locations_geteditdate]
ON  [dbo].[TBL_LOCATIONS]   
instead of update
AS
begin
declare @recs INT
select @recs = COUNT(*)
from dbo.TBL_LOCATIONS a
join inserted i on i.Location_ID = a.Location_ID
if @recs > 0
update dbo.TBL_LOCATIONS
SET EditDate = GETDATE()
end
GO

alter TRIGGER   [dbo].[locations_move_topo]
ON  [dbo].[TBL_LOCATIONS]
for update   
AS   
BEGIN   
  update dbo.TBL_LOCATIONS
  set topo_name = dbo.TLU_TOPO_BOUNDS.name
  FROM  dbo.TBL_LOCATIONS
      inner join dbo.TLU_TOPO_BOUNDS
      on dbo.TBL_LOCATIONS.Location_ID = dbo.TBL_LOCATIONS.Location_ID
      where (TLU_TOPO_BOUNDS.Shape.STContains(TBL_LOCATIONS.SHAPE) = 1) ; 
END
接受的答复:

alter TRIGGER   [dbo].[locations_geteditdate]
ON  [dbo].[TBL_LOCATIONS]   
for update 
as
begin
update dbo.TBL_LOCATIONS
SET EditDate = GETDATE()
from dbo.TBL_LOCATIONS locn
inner join inserted i on i.location_id = locn.Location_ID
end
GO
在if条件下(在
位置中\u geteditdate
),没有where子句;因此,它包括所有记录:

if @recs > 0
update dbo.TBL_LOCATIONS
SET EditDate = GETDATE()
WHERE ???
end
您正确地使用了插入的
表来查看已更新的内容,但仅用于标识记录计数

因此,在读取您放入触发器的代码时,您试图做的似乎只是对表应用一个时间戳,以在表被更新时显示它

您对此至少有以下选项:
1.如果您实际上不需要可识别的datetime,您可以使用时间戳字段而不是datetime,并使其自动更新。
2.如果可以控制表更新的执行位置,则只需在那里设置
EditDate
(即在存储过程中)

但是,假设您想要一个可识别的日期时间,并且无法控制表的更新发生在何处,这就是为什么您要实现一个触发器而不仅仅是一个proc set
EditDate
,那么您需要继续使用以下两种类型的触发器之一:

A) 因此,如果您坚持使用“而不是”触发器,您需要了解它将替换可能发生的更新。因此,你有责任去做它将要做的工作。您可以逐列检查已更改的内容:
e、 g

。。。对每列重复此操作(如果有意义,可以合并更新)

B) 或者,您可以更改为“after”触发器,允许进行更新(这样您就不必逐列编码以检查更新内容),但随后必须检查
EditDate
列,如果是
EditDate
列已更改,则不执行更新。如果你不这样做,你将在一个无限循环-你的进程调用触发器调用触发器等

i、 e.类似于:

IF NOT UPDATE(EditDate)
BEGIN
   UPDATE dbo.TBL_LOCATIONS
   SET EditDate = GETDATE()
   FROM dbo.TBL_LOCATIONS locn
     INNER JOIN inserted i on i.locn_id = locn.locn_id
END

很好的提示,但是我应该向where语句传递什么呢?tbl_位置中20个不同列中的任何一个可能已更改,例如,用户可能已更新(1)一条记录的nvchar列;(2) 一个int列表示1条记录;或者(3)多列多记录我扩展了答案,提供了另一种方法forward@tpcolson,如果locn.locn_id是您的主键,则无需更新以包括对已接受答案的修改…这似乎有效。谢谢!
IF NOT UPDATE(EditDate)
BEGIN
   UPDATE dbo.TBL_LOCATIONS
   SET EditDate = GETDATE()
   FROM dbo.TBL_LOCATIONS locn
     INNER JOIN inserted i on i.locn_id = locn.locn_id
END