【问题标题】:Trigger did not run?触发器没有运行?
【发布时间】:2017-10-27 21:01:57
【问题描述】:

我在插入/更新/删除/之后有一个触发器。它应该根据 Transaction 表中的交易来计算 Account 表上的 Balance。它在事务表上。我很少遇到余额差异,因此决定添加一些登录信息。它转储插入+删除的表(它们组合成一个表变量)和触发它的 tsql 语句。从我的日志来看,似乎 trigger 没有为某些插入到 Transaction 表中而触发。这会发生吗?是否有任何 TSQL 语句可以在不触发触发器的情况下更改表数据(截断表等除外)?

这里是触发器

CREATE TRIGGER [dbo].[trg_AccountBalance]
ON [dbo].[tbl_GLTransaction] 
AFTER INSERT, UPDATE, DELETE
AS

set nocount on
begin try
    declare @OldOptions int = @@OPTIONS

    set xact_abort off

    declare @IsDebug bit = 1

    declare @CurrentDateTime datetime = getutcdate()
    declare @TriggerMessage varchar(max), @TriggerId int

    if @IsDebug = 1
    begin

        select @TriggerId = isnull(max(TriggerId), 0) + 1
        from uManageDBLogs.dbo.tbl_TriggerLog

        declare @dbcc_INPUTBUFFER table(EventType nvarchar(30), Parameters Int, EventInfo nvarchar(4000) )  

        declare @my_spid varchar(20) = CAST(@@SPID as varchar(20)) 

        insert @dbcc_INPUTBUFFER  
        exec('DBCC INPUTBUFFER ('+@my_spid+')')

        select @TriggerMessage = replace(EventInfo, '''', '''''') from @dbcc_INPUTBUFFER

        insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
        values (@TriggerId, @TriggerMessage, @CurrentDateTime)
    end

    declare @Oper int
    select @Oper = 0 

    -- determine type of sql statement
    if exists (select * from inserted) select @Oper = @Oper + 1
    if exists (select * from deleted) select @Oper = @Oper + 2

    if @IsDebug = 1
    begin
        select @TriggerMessage = '@Oper = ' + convert(varchar, @Oper)

        insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
        values (@TriggerId, @TriggerMessage, @CurrentDateTime)
    end

    if @Oper = 0 return -- No data changed

    declare @TomorrowDate date = dateadd(day, 1, convert(date, getdate()))
    declare @CurrentDate date = convert(date, getdate())

    -- transactions from both inserted and deleted tables
    declare @tbl_Trans table (FirmId int, GLAccountId int, 
        AmountDebit money, AmountCredit money, "Status" char(1), TableType char(1))

    declare @tbl_AccountCounters table (FirmId int, GLAccountId int, Balance money) 
    declare @IsChange bit = null

    insert into @tbl_Trans (FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", TableType)
        select FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", 'I'
        from inserted
        union
        select FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", 'D'
        from deleted

        if @IsDebug = 1
        begin
            select @TriggerMessage = (select * from @tbl_Trans for xml path ('tbl_Trans'))

            insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
            values (@TriggerId, @TriggerMessage, @CurrentDateTime)
        end

        insert into @tbl_AccountCounters (FirmId, GLAccountId, Balance)
            select FirmId, GLAccountId, 0
            from @tbl_Trans
            group by FirmId, GLAccountId

        if @Oper = 1 or @Oper = 2 -- insert/delete
        begin
            update @tbl_AccountCounters
            set Balance = cnt.TransSum
            from @tbl_AccountCounters as ac join
            (
                select trans.FirmId, trans.GLAccountId, 
                    isnull(sum((trans.AmountDebit - trans.AmountCredit) * iif(trans.TableType = 'I', 1, -1)), 0)  as TransSum
                from @tbl_Trans as trans
                where trans.Status = 'A'
                group by trans.FirmId, trans.GLAccountId
            ) as cnt on ac.FirmId = cnt.FirmId and ac.GLAccountId = cnt.GLAccountId

            select @IsChange = 1
        end
        else
        begin
            if update(AmountDebit) or update(AmountCredit) or update(Status) or update(GLAccountId)
            begin
                update @tbl_AccountCounters
                set Balance = cnt.TransBalance
                from @tbl_AccountCounters as ac join
                    (select trans.FirmId, trans.GLAccountId, isnull(sum(trans.AmountDebit - trans.AmountCredit), 0) as TransBalance
                    from dbo.tbl_GLTransaction as trans
                    where trans."Status" = 'A' and exists (select 1 from @tbl_AccountCounters as ac 
                        where ac.GLAccountId = trans.GLAccountId and ac.FirmId = trans.FirmId)
                    group by trans.FirmId, trans.GLAccountId) as cnt on 
                        ac.FirmId = cnt.FirmId and ac.GLAccountId = cnt.GLAccountId

                select @IsChange = 0
            end
        end

        if @IsDebug = 1
        begin
            select @TriggerMessage = '@IsChange = ' + isnull(convert(varchar, @IsChange), 'null')

            insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
            values (@TriggerId, @TriggerMessage, @CurrentDateTime)

            select @TriggerMessage = (select * from @tbl_AccountCounters for xml path ('tbl_AccountCounters'))

            insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
            values (@TriggerId, @TriggerMessage, @CurrentDateTime)
        end

        if @IsChange is not null
        begin
            update tbl_GLAccount
            set tbl_GLAccount.Balance = iif(@IsChange = 1, cnt.Balance + acc.Balance, cnt.Balance),
                tbl_GLAccount.LastUpdate = getutcdate(),
                tbl_GLAccount.LastUpdatedBy = 1 
            from @tbl_AccountCounters as cnt join dbo.tbl_GLAccount as acc on
                cnt.FirmId = acc.FirmId and cnt.GLAccountId = acc.GLAccountId
        end
        if (16384 & @OldOptions) = 16384 set xact_abort on
    end try
    begin catch
        declare @ErrorLine varchar(max)
        select @ErrorLine = uManageDb.dbo.udf_GetErrorInfo()

        insert into uManageDb.dbo.tbl_TriggerError ("Name", "Message", CreateDate) 
        values ('AccountingDB..trg_AccountBalance', @ErrorLine, GETUTCDATE())
    end catch

【问题讨论】:

  • 我不认为'这里是一些代码' 或者'从我的日志来看我没有显示'给读者非常有用。另一种方法似乎是让读者翻阅不熟悉的代码并猜测您为什么使用您使用的条件。什么没有被插入到您希望出现的日志中?考虑到您在触发器中编写的条件,为什么要插入它?有什么条件?
  • 我只是不想用我的长代码把这个地方搞得一团糟。第一条语句写入日志 (@IsDebug = 1) 启动触发器的 sql 查询。我的日志中有 5 个触发器运行,添加了 6 个事务,但事务表有 14 个。不知何故,他们的日志中没有记录(至少那个 sql 查询)。我现在把所有的触发文本放进去:)
  • set xact_abort = off 是尝试跳过错误。
  • 对于触发器引用的任何列,您应该发布未按预期捕获的输入数据示例。

标签: sql-server


【解决方案1】:

我想我已经找到了。我有这一行:

select .. from inserted 
union 
select .. from deleted

他们以 300 美元的价格插入了 5 个 trans 和 100 美元的 4 个 trans。我的@tbl_Trans 中有 2 条记录(300 和 100)(它在日志中)。这可能是错误。因此,必须记录 hellps 并触发运行。

我将用 union all 替换 union。

【讨论】:

  • 我有一个新版本的触发器,它没有:“if Oper = 1 or Oper = 2 -- insert/delete”并且只计算余额差异。我可能很快就会开始出现故障。所以我可能不得不很快再问你一次:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 2022-10-13
相关资源
最近更新 更多