@@ ERROR始终等于零

时间:2013-12-30 19:49:44

标签: sql-server sql-server-2008

我有以下代码:

BEGIN TRY
   EXEC (@action_sql);
END TRY
BEGIN CATCH
   SELECT @change_id AS ChangeId,
          @action_sql AS sqlAttempted,
          ERROR_MESSAGE () AS ErrorMessage,
          ERROR_NUMBER () AS ErrorNumber,
          ERROR_SEVERITY () AS ErrorSeverity,
          ERROR_LINE () AS ErrorLine;
END CATCH;

IF @@ERROR = 0
   BEGIN
      PRINT '@@ERROR = ' + CAST (@@ERROR AS VARCHAR (10))
      PRINT 'COMMIT';
      COMMIT TRANSACTION;
   END
ELSE
   BEGIN
      PRINT '@@ERROR = ' + CAST (@@ERROR AS VARCHAR (10))
     PRINT 'ROLLBACK';
     ROLLBACK TRANSACTION;
   END;

当我在@action_sql中放入有效或无效的SQL语句时,我总是打印

@@ERROR = 0
COMMIT
即使@@ERROR无效,

action_sql也始终返回零。

确定是否发生某种错误的最简单方法是什么?

谢谢,

2 个答案:

答案 0 :(得分:3)

这是因为@@ERROR的值重置为0,即在TRY CATCH块中捕获并处理后,没有错误。因此,正确的方法是捕获并存储变量中的错误值(如果有),然后根据变量是否表明发生了错误,使用这些变量采取进一步的操作。

请参阅下面的示例代码。 @action_sql在第一种情况下无效,您将看到打印出的错误代码。在第二种情况下,@action_sql有效,您将看不到任何打印出的错误代码。

第一个示例:无效@action_sql

declare @action_sql NVARCHAR(2000);
declare @change_id INT
declare @ErrorNumber int
declare @ErrorMessage  NVARCHAR(2000);

set @action_sql  = 'select * from sysobj;'

BEGIN TRY
   EXEC (@action_sql);
END TRY
BEGIN CATCH    
          SELECT 
          @ErrorMessage =  ERROR_MESSAGE(),
          @ErrorNumber = ERROR_NUMBER()
          -- ERROR_SEVERITY () AS ErrorSeverity,
          -- ERROR_LINE () AS ErrorLine;
END CATCH;

IF @ErrorNumber = 0
   BEGIN
      PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
      PRINT 'COMMIT';
      --COMMIT TRANSACTION;
   END
ELSE
   IF (@ErrorNumber > 0)
   BEGIN
      PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
     PRINT 'ROLLBACK';
     --ROLLBACK TRANSACTION;
   END;

第二个样本:有效@action_sql

declare @action_sql NVARCHAR(2000);
declare @change_id INT
declare @ErrorNumber int
declare @ErrorMessage  NVARCHAR(2000);

set @action_sql  = 'select top 10 * from sysobjects;'

BEGIN TRY
   EXEC (@action_sql);
END TRY
BEGIN CATCH    
          SELECT 
          @ErrorMessage =  ERROR_MESSAGE(),
          @ErrorNumber = ERROR_NUMBER()
          -- ERROR_SEVERITY () AS ErrorSeverity,
          -- ERROR_LINE () AS ErrorLine;
END CATCH;

IF @ErrorNumber = 0
   BEGIN
      PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
      PRINT 'COMMIT';
      --COMMIT TRANSACTION;
   END
ELSE
   IF (@ErrorNumber > 0)
   BEGIN
      PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
     PRINT 'ROLLBACK';
     --ROLLBACK TRANSACTION;
   END;

答案 1 :(得分:2)

一旦发生错误,就会填充@@ERROR函数,并且如果在此函数之后执行任何其他语句,则其值将重置为NULL,因此您必须使用变量来捕获值执行完陈述后的@@ ERROR函数

因此,要预测错误发生的位置,然后将其值存储到变量中,当你有TRY..CATCH个阻止时,它实际上是过度杀戮。

由于您正在使用TRY..CATCH块,因此您根本不需要使用@@ ERROR函数。只需更改代码的顺序。

像这样......

BEGIN TRY
 BEGIN TRANSACTION

   EXEC (@action_sql); --<-- if an error occurs here control jumps to catch block and
                          -- following lines of code never gets executed. (I mean in case of an error)
   PRINT 'COMMIT';        
   COMMIT TRANSACTION;
END TRY

BEGIN CATCH
 IF @@TRANCOUNT <> 0      --<-- Once an error occurred check for any open trans
   ROLLBACK TRANSACTION      -- if there is one ROLLBACK it.

   SELECT @change_id AS ChangeId,         --<-- Rest of the ERROR Functions 
          @action_sql AS sqlAttempted,
          ERROR_MESSAGE () AS ErrorMessage,
          ERROR_NUMBER () AS ErrorNumber,
          ERROR_SEVERITY () AS ErrorSeverity,
          ERROR_LINE () AS ErrorLine;
END CATCH;

现在,如果您的BEGIN块中有Explicit Transaction TRY,如果发生任何错误,执行将停在那里,控件将跳转到CATCH块。

然后在那里你可以使用@@TRANCOUNT检查任何OPEN TRANSACTION,如果打开则回滚它并使用ERROR MESSAGES获取有关错误的所有其他信息。