2012-09-17 63 views
1

后,这是保持简单的跟踪更改数据库行的最佳方式:触发和更新的行中的SQL Server,它已经更新

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。

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

马克

+0

使用'GETDATE()'中的查询被追逐的目标,影响性能,并且可能产生好奇的结果,例如随着日期的变化。在变量中捕获当前日期/时间几乎总是一个更好的主意,然后根据需要使用该值。在存储过程中,这在多个语句中更重要。多次使用'GetDate()'的最常见原因是捕获长时间运行操作的开始和结束时间。 – HABO

+1

@HABO,除非绝对重要的是所有的行都标记了完全相同的更新时间戳,我认为在这种情况下不存在太多问题。 –

+0

我不确定,但我认为在一个声明中,getdate()将为每一行返回相同的日期/时间。 –

回答

15

inserted是一个伪表,它肯定包含了所有受到这种UPDATE陈述权行(我假设DISTINCT是没有必要的,如果ID主键 - 虽然这是很难说的表是什么名字如121s)。是否所有实际上都有已更改值是您在应用修改的日期/时间之前可能要考虑验证的另一件事。除非,我可能会做这种方式:

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 

如果你想有一个100%万无一失的保证,他们都更新了具有相同时间戳(虽然我不知道如果我曾经在这种情况下,使用见过多个值):

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; 

它如果foo是可以为空的,则变得更加复杂,但这是一般模式。

+0

谢谢 - 我已经将此标记为答案,正如我从您的原始评论中知道的那样,您必须立即着手处理它。我也非常感谢其他答案,并且还有+ 1d - 谢谢大家 - 这里的帮助令人难以置信! – Mark

+0

如果您不介意,只需快速查询以扩展您的答案......我确实看到更新时间戳的另一个参考,仅当某些列(可能不止一个,如您的示例中)发生更改时:如果update([name])或update([address])开始....那可能吗? (对于信息121s是一个与工作人员一对一会议,以表现更新性能等) - 再次感谢,马克 – Mark

+0

@fixit不,你不能依靠这一点。如果我说'UPDATE foo SET bar = bar'或'bar'已经是'1'并且我说'UPDATE foo SET bar = 1',那么'UPDATE(bar)'将返回true,即使我没有改变值。 –

2

插入的是包含受该触发触发器(插入/更新)操作的行的表。所以你的触发器是正确的。如果Id是主键,那么您不需要明确(从插入的选择ID就足够了)。如果Id不是主键,那么你的触发器是错误的,因为你可能最终会更新,那么你应该。

1

虽然很多,不仅仅是#2,但在世界各地都会告诉你的触发器是邪恶的,我会说,他们持有价值时,不被滥用他们。在这里,如果你想使用这个触发器,它似乎有效,Inserted表包含由触发触发器的语句更新的行 - 这是正确的,除非ID是主键DISTINCT大概可以去除。

但是,如果你有灵活性的另一种选择,是使用timestamp柱代替。但是,不要被迷惑,在timestamp相关的日期和时间。所以如果你需要日期和时间,坚持那里的东西。

+0

使用时间戳实际上与我所建议的相反。通常情况下,人们不得不离开时间戳,因为他们真正想要的是日期/时间,而不是一些不可读的rowversion二进制值,它们无法帮助他们追踪行被修改时的情况。 –

+0

我知道时间戳 - 我想这只是措辞不佳 - 我知道它将来会被贬值。 – Mark