SQL Server 2019中sp_send_dbmail执行EXECUTE失败但SELECT成功
解决SQL Server 2019中sp_send_dbmail执行存储过程报错的问题
问题重现
在SQL Server 2017中正常运行的代码:
EXECUTE msdb.dbo.sp_send_dbmail @recipients = 'mymail@myaddress', @subject = 'DailySecurityCheck', @query = 'EXECUTE [database].[dbo].[pr_DailySecurityCheck]'
迁移到SQL Server 2019后抛出错误:
Failed to initialize sqlcmd library with error number -2147467259
已知情况:
- 在SSMS中直接执行
EXECUTE [database].[dbo].[pr_DailySecurityCheck]正常 - 将@query替换为SELECT语句时,sp_send_dbmail能正常运行
- 尝试添加
@query_result_header = 1和@query_no_truncate = 0参数无效
可能的解决方案
1. 规范存储过程的结果集输出
SQL Server 2019对sp_send_dbmail的@query结果集兼容性要求更严格:
- 检查存储过程返回的结果集列名,避免空格、非ASCII字符等特殊格式
- 若存储过程返回多个结果集,改用临时表统一捕获后再查询,示例:
EXECUTE msdb.dbo.sp_send_dbmail @recipients = 'mymail@myaddress', @subject = 'DailySecurityCheck', @query = ' CREATE TABLE #TempResult (列1 INT, 列2 VARCHAR(50), ...); -- 匹配存储过程输出列 INSERT INTO #TempResult EXECUTE [database].[dbo].[pr_DailySecurityCheck]; SELECT * FROM #TempResult; DROP TABLE #TempResult; '
2. 验证权限配置
SQL Server 2019中sp_send_dbmail调用sqlcmd的权限逻辑有调整:
- 确保执行账号属于msdb数据库的
DatabaseMailUserRole角色,同时对目标数据库有EXECUTE权限 - 若存储过程涉及跨数据库对象,确认账号有对应的跨数据库访问权限
3. 统一SET选项环境
存储过程的SET选项与sqlcmd默认环境不一致可能导致初始化失败,在存储过程开头显式设置兼容选项:
SET ANSI_NULLS ON; SET ANSI_PADDING ON; SET ANSI_WARNINGS ON; SET CONCAT_NULL_YIELDS_NULL ON; SET QUOTED_IDENTIFIER ON; SET NUMERIC_ROUNDABORT OFF; SET ARITHABORT ON;
4. 临时调整数据库兼容级别(排查用)
若以上方法无效,可临时将目标数据库兼容级别设为SQL Server 2017的140,验证是否为兼容级别导致:
ALTER DATABASE [database] SET COMPATIBILITY_LEVEL = 140;
注:这只是临时排查方案,长期建议适配SQL Server 2019的兼容级别。
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

