SQL Server 2008创建/上次更新触发器问题

时间:2013-03-19 09:30:34

标签: sql sql-server-2008 datetime triggers

我正在使用此触发器在表格中填写CreatedDateLastUpdated列(类型datetime):

CREATE TRIGGER trCreatedDate ON [LasMTest]
FOR INSERT 
AS
    UPDATE [LasMTest] 
    SET [LasMTest].Created = getdate(),
        [LasMTest].LastModified = getdate()
    FROM [LasMTest] 
    INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID]
GO

当我检查表格时,日期只有几分之一秒。

Created LastModified    ID
2013-03-19 09:24:32.920 2013-03-19 09:24:32.930 4
2013-03-19 09:26:39.890 2013-03-19 09:26:39.900 5

如何修改触发器以确保它们都是准确的时间?

3 个答案:

答案 0 :(得分:2)

这是导致问题的两个触发器的交互。

相反,如果您将两列都设置为默认getdate()并放弃了insert触发器,那么它应该有效 - INSERT也不会导致UPDATE

另一种方法是将INSERT触发器创建为INSTEAD OF触发器,执行INSERT而不是UPDATE(因此,同时避免UPDATE触发器触发)。


如果你确实想把它写成INSTEAD OF触发器,那就像是:

CREATE TRIGGER trCreatedDate ON [LasMTest]
INSTEAD OF INSERT 
AS
    INSERT INTO LasMTest (/* Column List */,Created,LastModified)
    SELECT /* Column List */,getdate(),getdate() from inserted
GO

INSERT进入INSTEAD OF触发器中的触发表时(谢天谢地)会导致触发器被递归触发。如果IDIDENTITY列,则它应显示在上面的列列表中(尚未生成)。

答案 1 :(得分:0)

试试这个:

CREATE TRIGGER trCreatedDate ON [LasMTest]

FOR INSERT 

AS
Declare @CurrentDate Datetime
Set @CurrentDate=getdate()
UPDATE [LasMTest] SET [LasMTest].Created=@CurrentDate,[LasMTest].LastModified=@CurrentDate

FROM [LasMTest] INNER JOIN Inserted ON [LasMTest].[ID]= Inserted.[ID]

GO

答案 2 :(得分:0)

从INSERT执行更新时,您基本上希望避免使用UPDATE触发器。这称为Nested Triggers。一个简单的解决方案是使用CONTEXT_INFO()与已经在INSERT触发器中的嵌套UPDATE触发器代码进行通信,因此它会抑制自身:

CREATE TRIGGER trCreatedDate ON [LasMTest]
FOR INSERT 
AS
    SET CONTEXT_INFO 0xDEADBEEF;
    UPDATE [LasMTest] 
    SET [LasMTest].Created = getdate(),
        [LasMTest].LastModified = getdate()
    FROM [LasMTest] 
    INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID];
    SET CONTEXT_INFO NULL;
GO

CREATE TRIGGER trModifiedDate ON [LasMTest]
FOR UPDATE
AS
    DECLARE @context varbinary(128);
    SET @context = CONTEXT_INFO();
    IF @context is NULL
    BEGIN
       UPDATE [LasMTest] 
          SET [LasMTest].LastModified = getdate()
        FROM [LasMTest] 
        INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID];
    END
GO

然而,这种方法很脆弱。异常可以设置context_info并抑制会话中的所有后续UPDATE触发器。这需要添加TRY / CATCH块。并且您总是冒着使用CONTEXT_INFO自己的目的的应用程序的风险并破坏您的计划。

另一种解决方案是使UPDATE触发器变得智能。它可以检查UPDATE触发器中的UPDATE(Created),并在Created列被修改时禁止任何操作。这符合惯例,因为您知道更新Created列的唯一位置是INSERT触发器:

CREATE TRIGGER trModifiedDate ON [LasMTest]
FOR UPDATE
AS
    IF NOT UPDATE(Created)
    BEGIN
       UPDATE [LasMTest] 
          SET [LasMTest].LastModified = getdate()
        FROM [LasMTest] 
        INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID];
    END
GO