SQL Server查询sys.database_permissions时出现Invalid Object Name错误求助
分析你的
sys.database_permissions查询报错问题 你遇到的这种“先返回部分结果,随后抛出Invalid Object Name错误”的情况,结合你用sp_MSForEachdb遍历所有数据库的场景,大概率是以下几个原因之一:
1. 存在状态异常的数据库
sp_MSForEachdb会尝试遍历所有数据库(包括系统库),如果某个数据库处于以下状态,访问它的sys.database_permissions就会报错:
- 脱机(Offline)状态
- 还原中(Restoring)状态
- 可疑(Suspect)状态
- 只读(Read-Only)状态且当前会话没有足够的访问权限(虽然你说权限没问题,但可以再确认下这类库的权限)
比如当脚本执行到一个脱机的数据库时,[?].sys.database_permissions就会因为数据库无法访问而抛出对象不存在的错误。
2. sp_MSForEachdb的已知缺陷
这个存储过程是微软未正式公开的工具,存在不少小问题:
- 特殊数据库名称处理错误:如果你的数据库名称包含中括号(比如
My[DB]),[?]替换后会变成[My[DB]],这会导致SQL语法错误,触发对象不存在的报错。 - 跳过某些库的逻辑不稳定:它偶尔会错误地尝试访问一些本应跳过的系统库(比如
resource数据库,这个库是隐藏的,直接访问会报错)。
3. 系统视图依赖的底层系统表损坏
sys.database_permissions是基于系统表(比如sys.syspermissions、sys.sysusers等)构建的视图,如果某个数据库的这些底层系统表存在损坏(比如页错误、无效条目),查询视图时就会抛出异常。这种情况通常伴随其他数据库异常,比如DBCC检查会报错。
4. 数据库兼容性级别过低
如果某个数据库的兼容性级别设置为SQL Server 2000(级别80)或更低,虽然sys.database_permissions视图在高版本SQL Server中依然存在,但低兼容性级别下视图的查询逻辑可能出现冲突,导致报错。
排查建议
你可以先修改脚本,添加错误捕获和数据库状态检查,定位到具体出问题的数据库:
EXEC sp_MSForEachdb ' BEGIN TRY IF DATABASEPROPERTYEX(''?'', ''Status'') = ''ONLINE'' BEGIN SELECT distinct p.permission_name , ''?'' AS DatabaseName FROM [?].sys.database_permissions p END END TRY BEGIN CATCH SELECT ''Error accessing database: '' + ''?'' AS ErrorInfo, ERROR_MESSAGE() AS ErrorDetails END CATCH '
这个脚本会跳过离线数据库,并捕获报错的库和具体错误信息,帮你精准定位问题根源。
内容的提问来源于stack exchange,提问作者Vaseem Akram




