【问题标题】:SQL know what statement activated a trigger if the trigger fails如果触发器失败,SQL 知道哪个语句激活了触发器
【发布时间】:2014-04-07 00:37:26
【问题描述】:

我在 C# 应用程序中使用 SQL Server,并且正在使用批处理语句。我遇到的问题是在语句失败的情况下,无论出于何种原因,我都需要知道哪个语句失败并返回它。

我已经成功地做到了这一点,我在 SQL 语句周围放置了一个 try catch(所以如果它失败就不会退出),然后 C# cmd.ExecuteQuery 返回受影响的行数。

我现在遇到的问题是,如果由于触发器而发生故障,则触发器在原始批次的try catch 之外,因此不会被捕获,而是会被C# 应用程序。在这一点上,批次的状态迷失了,整个事情都失败了。

我需要某种方式来了解哪个语句(或到目前为止受影响的行数,或批处理中的索引)触发了导致异常的触发器。无论我可以在 SQL 还是 C# 中做某事,我都愿意接受任何事情。

谢谢。

【问题讨论】:

  • 您可以使用@@RowCount 来处理受影响的行并从存储过程中返回它们。如果您有触发器,则可以记录更新或插入的数据,也可以将其包含在另一个 try/catch 中,如果触发器失败,则将其记录在失败日志表中。
  • @Nilesh 我不确定我是否听懂了你的意思。所以说我有一批带有一堆插入语句的批次。该表有一个插入触发器,碰巧失败。如果触发器导致事务失败并退出,我如何调用存储过程来调用@@RowCount。另外,您是否还建议我在触发器周围添加一个 try-catch ?并且在捕获中,记录表中的任何数据?
  • @@RowCount 将在存储过程中使用。当您插入某些东西并假设插入触发器被触发并且它失败时,在这种情况下,@@RowCount 将没有任何值,因此触发器中的 try/catch 将让您保存正在执行操作的数据错误。这只是一个想法,因为您需要知道哪个语句/触发器导致了异常。如果您碰巧在存储过程中有一个 try/catch,我认为您无法确定哪个触发器未能执行。
  • 如果触发器失败(但你真的应该编写没有失败的触发器),它将在原始语句中的任何错误发生的同时报告失败。我不确定您为什么认为它会发生在 try/catch 的“外部” - 在任何相关触发器也执行之前,语句不会被报告为完整。
  • @Damien_The_Unbeliever 但说我有一个声明,例如 BEGIN TRY INSERT INTO JAZZHANDS VALUES (2) END TRY BEGIN CATCH END CATCH。如果表 JAZZHANDS 有一个在其他表中插入任何内容的触发器,则如果该触发器失败,它将不会循环返回并从原始插入的 CATCH 中捕获。交易完全失败。

标签: c# sql .net sql-server triggers


【解决方案1】:

这不是答案,但对于评论来说太大了,需要格式化。

假设我有一个语句,例如 BEGIN TRY INSERT INTO JAZZHANDS VALUES (2) END TRY BEGIN CATCH END CATCH。如果表 JAZZHANDS 有一个在其他表中插入任何内容的触发器,则如果该触发器失败,它将不会循环返回并从原始插入的 CATCH 中捕获。交易完全失败

我不知道你为什么这么想。以下 SQL:

create table JazzHands (ID int not null,constraint CK_ID_JH CHECK (ID < 10))
go
create table JazzHands2 (ID int not null,constraint CK_ID_JH2 CHECK (ID < 5))
go
create trigger T_JazzHands on JazzHands after insert
as
    insert into JazzHands2(ID)
    select ID from inserted
go
--1
begin try
    insert into JazzHands (ID) values (11)
    PRINT 'No error 1'
end try
begin catch
    Print 'error 1'
end catch
go
--2
begin try
    insert into JazzHands (ID) values (6)
    PRINT 'No error 2'
end try
begin catch
    Print 'error 2'
end catch
go
--3
begin try
    insert into JazzHands (ID) values (1)
    PRINT 'No error 3'
end try
begin catch
    Print 'error 3'
end catch
go

生产:

(0 row(s) affected)
error 1

(0 row(s) affected)

(0 row(s) affected)
error 2

(1 row(s) affected)

(1 row(s) affected)
No error 3

两个表都包含一行。也就是说,与您的断言相反,当表本身的某些内容阻止插入成功,或者表上的 trigger 中的某些内容阻止插入成功时,会发生完全相同的错误处理,而且通常无法区分。


如果您确实有一个实际示例,其中触发器失败产生的行为与直接在桌面上的失败不同,请将此类示例编辑到您的问题中。

【讨论】:

  • 嗯...不太确定我之前搞砸了什么,但现在它就像你说的那样工作。很抱歉浪费了您的时间。
【解决方案2】:

您要查找的是最后一条语句,对吗?您可以通过调用DBCC INPUTBUFFER 从触发器内部获取此信息。

看看这是否有帮助:

SELECT session_id, TEXT
FROM sys.dm_exec_connections
CROSS APPLY sys.dm_exec_sql_text(most_recent_sql_handle) AS ST

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多