SQL Server时间戳触发器

时间:2015-10-20 15:30:11

标签: sql-server triggers

我对SQL的了解非常有限,因为我主要关注后端Ruby开发。然而,由于建筑的变化,并希望保持良好的设计;我决定在数据库级别而不是在后端级别设置时间戳。

现在,我的所有表都有两列:CreatedAtUpdatedAt,两者都有默认值GETDATE()

但是,我现在需要为UpdatedAt设置时间戳触发器,以便每次更新一行(或多行)时,这些行的UpdatedAt列都会获得一个全新的时间戳。

我在编写以下触发器时遇到问题。我收到一个错误:

  

'='

附近的语法不正确

我首先在Orders表上测试我的触发器,然后我计划将功能移到所有表中。

CREATE TRIGGER dbo.trgTimestampAfterUpdate
ON Dbo.Orders
AFTER UPDATE
AS
BEGIN
    IF EXISTS (SELECT * FROM inserted)
    BEGIN
        SET UpdatedAt = GETDATE()
    END
END

我知道在使用触发器时我可以访问插入和删除的虚拟表。我对此查询的想法是,我将使用inserted来区分哪些行已更新。如果有人能提供帮助那就太棒了,而且如果你不介意向我解释我的语法或思路会搞砸了什么,我将不胜感激。

1 个答案:

答案 0 :(得分:3)

您无法真正访问插入的表格。刚刚Set UpdatedAt =...是一个不完整的陈述。隐含地它对你有意义,但即使在你的触发器中,你也必须制作完整的SQL语句。

执行此操作的方法是JOIN到INSERTED表(在下面的示例中,我使用的是半连接)然后,您可以使用INSERTED表的内容执行另一个更新。

CREATE TRIGGER [dbo].[trgTimestampAfterUpdate] ON dbo.orders
    FOR UPDATE
AS
BEGIN
    IF NOT(UPDATE(UpdatedAt)) --Avoid triggers firing triggers
    BEGIN

        UPDATE  dbo.orders
        SET     UpdatedAt = GETDATE()
        WHERE   id IN ( SELECT id
                        FROM   inserted )

    END
END

此代码示例中需要注意两个非常重要的事项。首先使用触发器更新表将导致触发器再次触发(创建一个循环,该循环将增加,直到达到系统上嵌套触发器的最大级别。)我检查以确保它终止,如果你是仅更新updatedat列。

其次,永远不要假设插入的表中只有一行。类似下面的代码是非常常见的错误

DECLARE @id INT
SELECT @id = id FROM INSERTED 

UPDATE MyTable 
SET UpdatedAT = GETDATE() 
WHERE id = @id
--DON'T DO THIS!

这看起来是正确的,并且是一个常见的错误,但它只会更新1条记录,并且INSERTED表中可能有任意数量的记录。