错误后有没有办法回到TRY块?

时间:2011-09-28 10:08:13

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

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

  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,如果列确实存在。无论哪种方式,执行都会传递到catch块并且永远不会返回。

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

3 个答案:

答案 0 :(得分:2)

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


e.g。

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

不是您问题的直接答案,但您最好使用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