【发布时间】: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