【问题标题】:Transaction has ended in trigger. Batch has been aborted. Derived Attribute交易已在触发器中结束。批次已中止。派生属性
【发布时间】:2012-03-21 11:02:52
【问题描述】:

我有这个触发器:

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

【问题讨论】:

    标签: sql-server visual-studio-2008 triggers derived


    【解决方案1】:

    你为什么要在触发器中提交?为什么不处理多行插入或更新?您不能只声明变量并从 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 日或两者之间的任何时间。

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

    【讨论】:

    • 非常感谢您的回复...实际上我的前端一次只插入一条记录,因此代码。是的,我现在同意你关于年龄专栏的建议。这真是个坏主意。我也知道不需要打印语句。实际上它是为了检查目的而编写的,然后没有被删除。最后,您能推荐一个获取学生年龄的好方法吗?
    • 可能是一个仅在您实际需要年龄时才调用的函数。 stackoverflow.com/questions/57599/…
    • 我希望我能给你的不仅仅是一票!再次感谢您。
    • 只是好奇;为什么实际上会发生这种批次的流产?我知道基本原因是在触发器内部提交。但如果我不这样做,那批次会发生什么,以免导致流产?
    • 批处理被中止,因为您在触发器中提交,然后可能尝试再次提交 - 您执行插入的调用代码是否可能使用事务(BEGIN TRANSACTION 显式或使用连接上的事务属性)?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 2014-05-12
    相关资源
    最近更新 更多