1

我正在编写一个存储过程,它遍历服务器上的所有数据库,并用来自一些不同数据库的数据聚合填充一个表变量。有些数据库我不感兴趣,因为它们无关紧要。问题是当我的 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。

4

2 回答 2

4

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

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

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

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

于 2012-10-10T20:54:38.893 回答
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),将防止引发该错误。

于 2012-10-11T14:02:04.970 回答