我正在编写一个存储过程,它迭代服务器上的所有数据库,并使用来自不同数据库的 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。
答案 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),将防止引发该错误。