2

我有这个触发器:

CREATE trigger [dbo].[DeriveTheAge] on [dbo].[Student]
after insert,update
as
begin
    declare @sid as int;
    declare @sdate as date;
    select @sid= [Student ID] from inserted;
    select @sdate=[Date of Birth] from inserted;
    commit TRANSACTION
    if(@sdate is not null)
    begin
        update Student set Age=DATEDIFF(YEAR,@sdate,GETDATE()) where [Student ID]=@sid;
    end
    print 'Successfully Done'
end

正如它所暗示的那样,触发器会从出生日期自动计算派生属性“年龄”。但是当我执行插入时出现此错误:

(1 row(s) affected)
Successfully Done
Msg 3609, Level 16, State 1, Line 1
The transaction ended in the trigger. The batch has been aborted.

最初我避免了这个错误,因为尽管出现了错误,行仍在更新。但是现在当我从 FORNT END 插入一条记录时,该记录没有更新。相反,它抛出了这个异常:在此处输入图像描述

谁能帮帮我?

顺便说一句,我的是 SQL Server 2008 R2 和 Visual Studio 2010。

更正:记录仍在更新。但例外是维兰。

更新

CREATE TRIGGER [dbo].[DeriveTheAge] 
ON [dbo].[Student]
FOR INSERT, UPDATE
AS
BEGIN
    UPDATE s 
      SET Age = DATEDIFF(YEAR, [Date of Birth], CURRENT_TIMESTAMP)
      FROM dbo.Student AS s
      INNER JOIN inserted AS i
      ON s.[Student ID] = i.[Student ID]
      WHERE i.[Date of Birth] IS NOT NULL;
      commit transaction
END
GO
4

1 回答 1

8

你为什么要在触发器中提交?为什么不处理多行插入或更新?您不能只声明变量并从 insert 中分配它们 - 您认为更新 2、15 或 6000 行时会分配哪些值?

CREATE TRIGGER [dbo].[DeriveTheAge] 
ON [dbo].[Student]
FOR INSERT, UPDATE
AS
BEGIN
    UPDATE s 
      SET Age = DATEDIFF(YEAR, [Date of Birth], CURRENT_TIMESTAMP)
      FROM dbo.Student AS s
      INNER JOIN inserted AS i
      ON s.[Student ID] = i.[Student ID]
      WHERE i.[Date of Birth] IS NOT NULL;
END
GO

说了这么多,到底为什么需要触发器来计算某人的年龄?您现在可以在查询时从出生日期获取此信息,并且知道它是准确的,这与您存储在表中的过时值不同。请注意,如果他们的行超过一年未更新,则您在表中输入的年龄已过期。你什么时候回去更新表中所有行的年龄?一天一次?再少一点,您的 Age 专栏就完全不可靠且毫无意义。

此外,DATEDIFF(YEAR这不是首先计算年龄的可靠方法。它所做的只是计算已经跨越的年份边界的数量,它不知道这个人的实际生日是 1 月 1 日还是 12 月 31 日或两者之间的任何时间。

最后,我不会从触发器打印。当您不调试时,谁会使用该打印语句?

于 2011-09-05T17:14:05.247 回答