4

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

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。

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

标记

4

3 回答 3

25

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);
   -- WHERE EXISTS is same as INNER JOIN inserted AS i ON t.ID = i.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
  INNER JOIN inserted AS i 
  ON t.ID = i.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,因为 SQL Server 将无法匹配一侧有值而另一侧没有值(或两者都没有)的行。在这种情况下,你会这样做:

   AND 
   (
     t.foo <> i.foo
     OR (t.foo IS NULL AND i.foo IS NOT NULL)
     OR (t.foo IS NOT NULL AND i.foo IS NULL)
   );

有些人会说“我可以使用 COALESCE 或 ISNULL 来对抗一些魔法值”,如下所示:

WHERE COALESCE(t.foo, 'magic') <> COALESCE(i.foo, 'magic')

...我会警告你不要这样做,因为你会不断地寻找一些在数据中不存在的神奇值。

于 2012-09-17T15:25:57.683 回答
2

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

于 2012-09-17T15:22:41.367 回答
1

虽然很多人,不仅在 Stackoverflow 上,而且在世界各地都会告诉你触发器是邪恶的,但我要说的是,当它们没有被滥用时,它们是有价值的。在这里,如果您想使用此触发器,它似乎是有效的,并且该Inserted表包含由触发此触发器的语句更新的行 - 它是正确的,但如果是主键DISTINCT则可能会被删除。ID

但是,如果您有灵活性,另一种选择是使用timestamp列。但是,不要混淆,该timestamp列与日期和时间无关。因此,如果您需要日期和时间,请坚持使用那里的内容。

于 2012-09-17T15:24:08.387 回答