【问题标题】:Transact-SQL - how to prevent second batch from running if the first failed?Transact-SQL - 如果第一批失败,如何防止第二批运行?
【发布时间】:2011-09-17 09:48:26
【问题描述】:

在上一个问题Problem with alter then update in try catch with tran using Transact-SQL 中,我发现要让我的 SQL 正常工作,我必须将它分成两批。这是用于此的 SQL:

USE PUK;
GO
BEGIN TRANSACTION;
BEGIN TRY

   -- - Modify RETRIEVAL_STAT
   alter table dbo.RETRIEVAL_STAT add
      SOURCE nvarchar(10) NULL,
      ACCOUNTNUMBER nvarchar(50) NULL,
      PUK nvarchar(20) NULL;

END TRY
BEGIN CATCH
    SELECT
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_PROCEDURE() AS ErrorProcedure
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;
IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO


USE PUK;
GO
BEGIN TRANSACTION;
BEGIN TRY

   -- transform logic.
   UPDATE      dbo.RETRIEVAL_STAT
   SET         SOURCE = 'ABC',
               ACCOUNTNUMBER = ABC.ACCOUNTNUMBER,
               PUK = ABC.PUK
   FROM        RETRIEVAL_STAT RS
   INNER JOIN  ABC
   ON          RS.SERVICE_NUMBER = ABC.SERVICENUMBER;

  --- ... snip

END TRY
BEGIN CATCH
    SELECT
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_PROCEDURE() AS ErrorProcedure
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;
IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

我现在的问题是:如果第一批失败,我如何防止第二批运行?

感谢您的建议!

罗伯 :)

【问题讨论】:

  • @Martin Smith Ok sweet raiserror('Oh no a fatal error', 20, -1) with log 很好地完成了这项工作。谢谢。
  • @Martin Smith 再三考虑,我仍然缺少一些信息:如何检测错误情况?在上面的示例中,我尝试更改更改表的名称并将 RAISERROR 放在 catch 中。它没有工作。它告诉我找不到对象“dbo.RETRIEVAL_SdTAT”,因为它不存在或者您没有权限。并愉快地继续运行其余的 SQL。
  • 你试过这个答案吗? stackoverflow.com/questions/659188/…。它看起来像你想要的,但需要你在 SSMS 中使用 sqlcmd 或 sqlcmd 模式。
  • :on error exit 嗯,这似乎有效。谢谢。 :)

标签: tsql


【解决方案1】:

根据您评论中的其他信息,您遇到的问题是因为这不是可捕获的错误。

由于对象不存在,第一批解析失败,因此整个批处理无法执行(包括您的raiserror 语句)。

举个简单的例子

SELECT * FROM NonExistentTable

GO

SELECT 1 AS [SecondBatch]

返回

Msg 208, Level 16, State 1, Line 3
Invalid object name 'NonExistentTable'.


SecondBatch
-----------
1

解决这个问题的几种方法是使用动态 SQL 将每个批次放入一个子范围

BEGIN TRY
EXEC('SELECT * FROM NonExistentTable')
END TRY
BEGIN CATCH
RAISERROR('Oh no a fatal error', 20, -1) WITH LOG
END CATCH

EXEC('SELECT 1 AS [SecondBatch]')

返回

Msg 2745, Level 16, State 2, Line 5
Process ID 55 has raised user error 50000, severity 20. SQL Server is terminating this process.
Msg 50000, Level 20, State 1, Line 5
Oh no a fatal error
Msg 0, Level 20, State 0, Line 0
A severe error occurred on the current command.  The results, if any, should be discarded.

或者(因为变量将超出批次之间的范围)您可以在每批结束时SET CONTEXT_INFO,然后在下一批开始时检查。

BEGIN TRY
SELECT * FROM NonExistentTable
SET CONTEXT_INFO 1
END TRY
BEGIN CATCH

END CATCH
GO
IF CONTEXT_INFO() <> 1
   RETURN

BEGIN TRY
SELECT 1 AS [SecondBatch]
SET CONTEXT_INFO 2
END TRY
BEGIN CATCH   
END CATCH


GO

IF CONTEXT_INFO() <> 2
   RETURN

BEGIN TRY
SELECT 1 AS [ThirdBatch]
SET CONTEXT_INFO 3
END TRY
BEGIN CATCH   
END CATCH

【讨论】:

  • "不是可捕获的错误" - 是因为它破坏了编译吗?什么定义了可捕获的错误?我认为@Mikael Eriksson 有一个有效的简单建议::on error exit
猜你喜欢
  • 2012-10-25
  • 1970-01-01
  • 1970-01-01
  • 2020-03-28
  • 1970-01-01
  • 2020-01-24
  • 1970-01-01
  • 1970-01-01
  • 2015-12-01
相关资源
最近更新 更多