SQL Server 2014执行失败却返回RC=0的原因咨询
为什么SQL Server 2014中你的代码返回RC=0?
这其实是因为SQL Server 2014及以后版本中,sp_send_dbmail处理内部查询错误的方式和2008不一样了,再加上你的TRY/CATCH逻辑只监控了外层sp_ExecuteSQL的执行状态,才导致了这个差异。
让我拆解一下原因:
1. 版本间sp_send_dbmail的错误处理行为变化
- 在SQL Server 2008中,当
sp_send_dbmail的@Query参数指定的查询执行失败(比如不存在的数据库/表),这个错误会直接冒泡到调用sp_send_dbmail的上下文里。这时候sp_ExecuteSQL执行这段动态SQL就会触发错误,被你的TRY/CATCH捕获,@@ERROR返回对应的错误码14661,所以你的@rc被设为这个值。 - 但到了SQL Server 2014,微软调整了
sp_send_dbmail的错误处理逻辑:当内部查询执行失败时,它不会把这个错误抛到外层执行上下文,而是只输出一条信息性错误消息(就是你看到的Msg 22050),但sp_send_dbmail本身的调用是成功完成的,所以外层的sp_ExecuteSQL执行没有失败,返回值为0,你的TRY块正常执行,CATCH块根本没触发,@rc自然保持0。
2. 你的TRY/CATCH逻辑的局限性
你的代码里,TRY/CATCH只监控了sp_ExecuteSQL这个调用的执行结果,而不是sp_send_dbmail内部的查询错误。在2014的场景下,sp_ExecuteSQL确实成功执行了那段动态SQL(哪怕sp_send_dbmail内部的查询炸了),所以TRY块认为一切正常,不会进入CATCH块修改@rc的值。
3. 怎么正确捕获这类错误?
如果你想在2014+版本中检测到sp_send_dbmail的内部查询错误,应该直接检查sp_send_dbmail的返回值,而不是依赖外层的TRY/CATCH。修改你的动态SQL,让它捕获sp_send_dbmail的返回码:
declare @nsql nvarchar(4000), @rc int, @dbmail_rc int set @rc = 0 set @nsql = ' DECLARE @internal_rc INT; EXECUTE @internal_rc = msdb.dbo.sp_send_dbmail @subject = ''test sub'' , @recipients = ''joe.bloggs@myemail.com'' , @copy_recipients=''null'' , @blind_copy_recipients=''null'' , @body=''test body'' , @Query = ''select * from mydb..tlist'' , @query_result_header =0; SELECT @internal_rc;' begin try exec @RC = sp_ExecuteSQL @NSQL, N'@internal_rc INT OUTPUT', @dbmail_rc OUTPUT -- 这里判断sp_send_dbmail的返回值 IF @dbmail_rc <> 0 SET @rc = @dbmail_rc end try begin catch set @RC=@@ERROR end catch print @rc
这样,即使sp_send_dbmail不抛出外层错误,你也能通过它的返回值知道内部是否执行失败了。
内容的提问来源于stack exchange,提问作者jay
相关产品推荐
相关产品推荐

