【问题标题】:Is there a way to go back to TRY block after error?有没有办法在出错后返回 TRY 块?
【发布时间】:2011-11-26 17:59:39
【问题描述】:

如果表包含特定列,我想检查我的存储过程。如果存在这样的列,我想提出一个错误,因为它们是不允许的。首先我想出了下面的想法,这显然有一个我能理解的缺陷。

  BEGIN TRY 

  SET @sql = N'SELECT TOP 0 forbidden_column_name1 INTO #t1 FROM ' + @input_table ;
  EXEC @err = sp_executesql @sql ;
  IF @err = 0  -- i.e. if succeeds
    RAISERROR('Input table cannot contain ''forbidden_column_name1''. This name is reserved!', 16, 99) ;

  SET @sql = N'SELECT TOP 0 forbidden_column_name2 INTO #t1 FROM ' + @input_table ;
  EXEC @err = sp_executesql @sql ;
  IF @err = 0  -- i.e. if succeeds
    RAISERROR('Input table cannot contain ''forbidden_column_name2''. This name is reserved!', 16, 99) ;

  SET @sql = N'SELECT TOP 0 forbidden_column_name3 INTO #t1 FROM ' + @input_table ;
  EXEC @err = sp_executesql @sql ;
  IF @err = 0  -- i.e. if succeeds
    RAISERROR('Input table cannot contain ''forbidden_column_name3''. This name is reserved!', 16, 99) ;

  END TRY
  BEGIN CATCH
    IF ERROR_STATE() = 99
    BEGIN
      DECLARE @ErrorMessage NVARCHAR(4000);
      DECLARE @ErrorSeverity INT;
      DECLARE @ErrorState INT;

      SELECT 
          @ErrorMessage = ERROR_MESSAGE(),
          @ErrorSeverity = ERROR_SEVERITY(),
          @ErrorState = ERROR_STATE();

      RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
      RETURN ;
    END
    -- Do nothing and continue execution, if column doesn't exist
  END CATCH

此代码将仅检查forbidden_column_name1 的存在。不检查其他的,因为在检查forbidden_column_name1 期间必须引发异常:如果列不存在,则来自sp_executesql,或者如果列确实RAISERROR /em> 存在。无论哪种方式,执行都会传递到 catch 块并且永远不会回来。

我的问题是,如果错误实际上不是错误,但实际上是需要的东西,有没有办法强制执行回到 TRY 块。否则我必须将所有检查放在单独的 TRY/CATCH 块中,这使得代码看起来有点多余。

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql exception


    【解决方案1】:

    为什么不查询sys.columns,以确定这些列是否存在,而不是通过查询表来推断它们的存在?


    例如

    IF EXISTS(select * from sys.columns where object_id = OBJECT_ID(@table_name) and name in (
        'forbidden_column1','forbidden_column2','forbidden_column3'))
    BEGIN
        RAISERROR('One or more forbidden columns detected. Review the documentation',16,99)
        RETURN
    END
    
    --Proceed, knowing that the table doesn't contain the forbidden columns
    

    【讨论】:

    • @input_table 是一个完全限定的表名,例如 mydb.myschema.mytable。我不知道sys.columns 我应该查询哪个数据库。我需要提取数据库名称并使用动态 SQL 查询 sys.columns。当然是一个可行的选择。所以你认为我的问题的答案肯定是 NO?
    • 跨数据库确实有点棘手,同意。但是没有工具可以从 catch 块“恢复”到 try 块(我认为有些语言具有这种结构,T-SQL 不是其中之一)
    【解决方案2】:

    您必须将每个单独的 select 语句包装在 try/catch 块中。

    BEGIN TRY 
    
        SET @sql = N'SELECT TOP 0 forbidden_column_name1 INTO #t1 FROM ' + @input_table ;
        EXEC @err = sp_executesql @sql ;
        IF @err = 0  -- i.e. if succeeds
            RAISERROR('Input table cannot contain ''forbidden_column_name1''. This name is reserved!', 16, 99) ;
    END TRY
    BEGIN CATCH
        IF ERROR_STATE() = 99
            EXEC usp_RethrowError
    END CATCH
    

    为避免重复,您可以为此创建一个过程,其中包含表名和列名的参数。

    Definition of usp_RethrowError

    【讨论】:

      【解决方案3】:

      不是您问题的直接答案,但您最好使用 INFORMATION_SCHEMA 来确定这些列是否存在。

      类似:

      IF EXISTS (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE 
          TABLE_NAME = @input_table AND COLUMN_NAME IN ('forbidden_column_name1', 'forbidden_column_name2', 'etc'))
      BEGIN
          RAISERROR('idiot', 16, 99)
      END
      

      【讨论】:

      • 如果这不是问题的答案,为什么要发布它作为答案呢?应该是评论。无论如何,这是主观的。我更喜欢IF COL_LENGTH('table_name','column_name') IS NULL。不可移植,但RAISERROR
      • 它没有回答他的question,但它回答了他的problem,如问题中所述。我会把它放在评论中,但代码在 cmets 部分中的可读性不高。
      • 我撤回了我的反对票,因为这可能只是对您答案的前 6 个字的下意识反应。仍然看不到这在其他答案之上增加了任何东西。为什么INFORMATION_SCHEMA 会比sys.columns 更好?它仍然是数据库范围的。
      • INFORMATION_SCHEMA 视图遵循它们的 ISO 标准,使用它们将启用 applications to work correctly although significant changes have been made to the underlying system tables
      • 根据我的经验,这不是问题。 Microsoft 仍然支持 syscolumns 等作为向后兼容性视图。请注意,您提供的链接有一个很大的警告文本“对信息架构视图进行了一些更改,这些更改破坏了向后兼容性。”这与您试图提出的观点有些矛盾。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 2021-10-12
      • 2021-06-30
      • 2016-05-06
      • 2017-11-29
      相关资源
      最近更新 更多