更新后,在SQL Server中触发并更新到一行

时间:2012-09-17 15:18:54

标签: sql sql-server sql-server-2008

这是保持简单跟踪数据库行更改的最佳方法:

ALTER TRIGGER [dbo].[trg_121s] 
ON  [dbo].[121s]
  AFTER UPDATE
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

-- Insert statements for trigger here

update dbo.[121s]
set modified=getdate()
where id in 
(select distinct ID from Inserted)

END

因此,对[121s]中某行的任何更新都会导致更新已修改列。

它有效,但我不确定这是否是实现这一目标的最佳方法。

我对这条线路感到困惑:

(select distinct ID from Inserted)

...以及它如何知道它获得了正确的行ID。

感谢您的任何确认/澄清,

标记

3 个答案:

答案 0 :(得分:19)

inserted是一个伪表,它肯定包含受UPDATE语句影响的所有正确的行(我假设DISTINCT不是必需的,如果{{1主键 - 虽然很难用ID之类的名称来表示表的内容。在应用修改后的日期/时间之前,您是否可以考虑验证是否所有人都实际上已经更改了值。除此之外,我可能会这样做:

121s

如果你想要100%万无一失的保证他们都使用相同的时间戳更新(虽然我不知道在这个用例中我是否见过多个值):

ALTER TRIGGER [dbo].[trg_121s] 
ON [dbo].[121s]
AFTER UPDATE
AS 
BEGIN
  SET NOCOUNT ON;

  UPDATE t SET modified = CURRENT_TIMESTAMP
   FROM dbo.[121s] AS t
   WHERE EXISTS (SELECT 1 FROM inserted WHERE ID = t.ID);
END
GO

如果您想确保仅在列ALTER TRIGGER [dbo].[trg_121s] ON [dbo].[121s] AFTER UPDATE AS BEGIN SET NOCOUNT ON; DECLARE @ts DATETIME; SET @ts = CURRENT_TIMESTAMP; UPDATE t SET modified = @ts FROM dbo.[121s] AS t WHERE EXISTS (SELECT 1 FROM inserted WHERE ID = t.ID); END GO 更改值时发生更新,您可以说:

foo

如果 UPDATE t SET modified = @ts FROM dbo.[121s] AS t INNER JOIN inserted AS i ON t.ID = i.ID AND t.foo <> i.foo; 可以为空,则会变得更加复杂,但这是一般模式。

答案 1 :(得分:2)

Inserted是一个表,其中包含受触发(插入/更新)操作影响的行。所以你的触发器是正确的。如果Id是主键,那么您不需要distinct(从Inserted中选择id就足够了)。如果Id不是主键,那么您的触发器是错误的,因为您最终可能会更新更多内容。

答案 2 :(得分:1)

虽然很多,不仅仅是在Stackoverflow上,而是在全世界都会告诉你触发器是邪恶的,我会说它们在没有被滥用的情况下保持价值。在这里,如果你想使用这个触发器,它似乎是有效的,Inserted表包含由触发此触发器的语句更新的行 - 它是正确的,除非DISTINCT可能被删除ID {1}}是主键。

但是,如果您具有灵活性,另一个选项是使用timestamp列。但是,不要混淆,timestamp与日期和时间相关联。因此,如果您需要日期和时间,请坚持使用。