为何sp_msforeachdb设置AUTO_CLOSE的脚本未排除master等系统数据库
问题原因
核心原因:SQL Server 批处理预编译机制
你提交的脚本中,ALTER DATABASE ? SET AUTO_CLOSE OFF 属于传入sp_msforeachdb的整个批处理的一部分。SQL Server在执行批处理前,会先对所有语句做语法、权限、配置合法性校验,校验过程不受IF分支逻辑影响,不管IF条件最终是否会命中。
当遍历到master、tempdb这类系统库时,?被替换为对应库名后,整段语句为:
USE master IF DB_NAME() NOT IN('master','msdb','tempdb','model','ReportServer') ALTER DATABASE master SET AUTO_CLOSE OFF
哪怕IF条件明显为假,预编译阶段校验ALTER DATABASE master SET AUTO_CLOSE OFF时,就会触发「系统库不允许修改AUTO_CLOSE选项」的报错,根本不会走到IF逻辑的执行阶段。
次要问题:语法兼容性不足
脚本中直接在ALTER语句中使用?没有加方括号包裹,遇到带空格、特殊字符的数据库名时也会额外触发语法错误。
修复后的脚本
EXECUTE sp_msforeachdb ' IF ''?'' NOT IN(''master'',''msdb'',''tempdb'',''model'',''ReportServer'') BEGIN EXEC(''ALTER DATABASE ['' + ? + ''] SET AUTO_CLOSE OFF'') END '
修复逻辑说明
- 直接对
sp_msforeachdb替换后的库名?做排除判断,不需要额外执行USE ?再查询DB_NAME() - 只有符合条件的库才会通过动态SQL生成并执行
ALTER语句,系统库不会触发ALTER语句的预编译校验,自然不会报错 - 用
[]包裹库名,兼容带特殊字符、空格的数据库名
内容的提问来源于stack exchange,提问作者José Camilo
相关产品推荐
相关产品推荐

