如何从存储过程中捕获特定的异常类型?

时间:2012-10-10 20:13:53

标签: sql-server sql-server-2008 exception exception-handling cursor

我正在编写一个存储过程,它迭代服务器上的所有数据库,并使用来自不同数据库的 some 的数据的聚合来填充表变量。一些我不感兴趣的数据库,因为它们无关紧要。问题是当我的CURSOR遍历那些我不关心的数据库时,会在不存在的表上发出SELECT语句。如何忽略Invalid object name异常并继续处理?

修改

以下是我试图跳过不相关的数据库的方法:

DECLARE db_cursor CURSOR FOR

SELECT name
FROM MASTER.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb') 

OPEN db_cursor 

FETCH NEXT FROM db_cursor INTO @currentDatabaseName  

WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @sql = 'SELECT COUNT(Name) FROM ' + @currentDatabaseName + '.sys.Tables WHERE Name = ''SomeTableICareAbout'''

        INSERT INTO @tableSearchResult
        EXEC sp_executesql @sql

        SET @tableCount = (SELECT COUNT(*) FROM @tableSearchResult WHERE TableCount = 1)

        --If the table I care about was found, then do the good stuff
        IF @tableCount > 0
            ...

这种方法的问题是如果执行用户(在我的情况下是一个服务帐户)无法访问表上的SELECT,那么我永远不会知道该错误。如果用户没有SELECT访问权限,我希望引发该异常。但是,即使用户没有SELECT访问权限,它也可以在sys.Tables视图上进行SELECT。

2 个答案:

答案 0 :(得分:4)

您无法直接捕获错误208,因为它是在编译时和实际执行代码之前引发的名称解析错误。行为为documented:有关解释,请参阅“未受TRY ... CATCH构造影响的错误”部分,this question的答案有一些有趣的评论。

除了文档中的“解决方案”之外,您还可以使用动态SQL;错误将在此示例中捕获:

begin try
    exec('select * from dbo.ThisTableDoesNotExist');
end try
begin catch
    select error_number();
end catch;

如果您正在遍历所有数据库,那么您很可能无论如何都在某处使用动态SQL,因此这可能更适合您的情况。

答案 1 :(得分:1)

如果您在存储过程中执行此操作,则可以捕获错误(示例:http://msdn.microsoft.com/en-us/library/ms175976.aspx

此外,您可以更改动态SQL以执行此类操作

SET @sql = '
        If Exists(Select Name From  ' + @currentDatabaseName + '.sys.Tables 
            WHERE Name = ''SomeTableICareAbout'')' --+
        --Add Whatever the Good Stuff is
EXEC sp_executesql @sql

但是检查表是否存在,而不是从表中执行select count(1),将防止引发该错误。