通过存储过程从SSRS导出PDF:执行成功但未生成文件求助
SSRS报表导出PDF存储过程无文件生成问题排查与修复
问题概述
我正在创建一个从SSRS报表服务器导出PDF报表的存储过程,该报表需要名为ExportId的参数。存储过程执行成功,但未生成PDF文件,请问哪里操作有误?
原存储过程代码:
Alter PROCEDURE rsp_GenerateAndDeliverReports @ReportName NVARCHAR(100), @Parameter1Name NVARCHAR(100), @Parameter1Value NVARCHAR(100), @OutputFile NVARCHAR(100) AS BEGIN -- Variables DECLARE @executionID AS INT DECLARE @reportBytes AS VARBINARY(MAX) DECLARE @zipFilePath AS NVARCHAR(100) DECLARE @reportService AS INT -- Change the data type to INT -- Create an instance of the SSRS Execution Service EXEC sp_OACreate 'SSRS.ReportExecutionService', @reportService OUT -- Initialize the service EXEC sp_OASetProperty @reportService, 'Url', 'http://localhost/ReportServer/ReportExecution2005.asmx' -- Load Report 1 EXEC sp_OAMethod @reportService, 'LoadReport', NULL, @ReportName, NULL, @executionID OUT -- Set Report 1 Parameters EXEC sp_OAMethod @reportService, 'SetExecutionParameters', NULL, @Parameter1Name, @Parameter1Value -- Render Report 1 EXEC sp_OAMethod @reportService, 'Render', @reportBytes OUTPUT, 'PDF', NULL, NULL, NULL, NULL, NULL -- Close and release the service EXEC sp_OADestroy @reportService -- Save Report 1 as PDF DECLARE @sql NVARCHAR(MAX) SET @sql = 'DECLARE @file AS VARBINARY(MAX) SET @file = ' + CONVERT(NVARCHAR(MAX), @reportBytes, 1) + ' EXEC sp_writebytesfile @file, ''' + @OutputFile + '' EXEC sp_executesql @sql END EXEC rsp_GenerateAndDeliverReports @ReportName='/All Reports/Subreports/07_sub', @Parameter1Name ='ExportId', @Parameter1Value='2', @OutputFile='C:\Users\Public\Public Downloads\Report.pdf'
错误原因分析
1. SetExecutionParameters方法参数格式错误
SSRS的SetExecutionParameters方法要求传入**ParameterValue类型的数组对象**,而非直接传递单个参数名和值。原代码直接传字符串参数,导致报表参数未正确设置,可能引发渲染失败。
2. Render方法参数顺序不匹配
Render方法的官方参数顺序为:Format, DeviceInfo, Extension, MimeType, Encoding, Warnings, StreamIDs,原代码的参数传递顺序错误,导致@reportBytes无法正确接收渲染后的二进制数据。
3. 二进制数据拼接与写入存在问题
使用动态SQL拼接VARBINARY(MAX)类型数据时,CONVERT转换可能丢失数据或格式错误;同时未对sp_writebytesfile的执行结果做校验,无法确认文件写入是否成功。
4. 缺失OLE对象错误捕获
未添加sp_OAGetErrorInfo来捕获OLE自动化对象的执行错误,存储过程返回"成功"但实际OLE操作可能已失败。
修正后的存储过程代码
ALTER PROCEDURE rsp_GenerateAndDeliverReports @ReportName NVARCHAR(100), @Parameter1Name NVARCHAR(100), @Parameter1Value NVARCHAR(100), @OutputFile NVARCHAR(255) -- 增大长度避免路径截断 AS BEGIN SET NOCOUNT ON; -- 变量声明 DECLARE @reportService INT, @executionID INT, @reportBytes VARBINARY(MAX); DECLARE @paramArray INT, @paramObj INT; DECLARE @hr INT, @errMsg NVARCHAR(255); -- 创建SSRS执行服务实例 EXEC @hr = sp_OACreate 'ReportExecutionService.ReportExecutionService', @reportService OUT; IF @hr <> 0 GOTO OLE_ERROR; -- 设置服务URL EXEC @hr = sp_OASetProperty @reportService, 'Url', 'http://localhost/ReportServer/ReportExecution2005.asmx'; IF @hr <> 0 GOTO OLE_ERROR; -- 加载报表 EXEC @hr = sp_OAMethod @reportService, 'LoadReport', @executionID OUT, @ReportName, NULL; IF @hr <> 0 GOTO OLE_ERROR; -- 创建参数数组与参数对象 EXEC @hr = sp_OACreate 'ReportExecutionService.ParameterValue[]', @paramArray OUT; IF @hr <> 0 GOTO OLE_ERROR; EXEC @hr = sp_OACreate 'ReportExecutionService.ParameterValue', @paramObj OUT; IF @hr <> 0 GOTO OLE_ERROR; -- 设置参数名和值 EXEC @hr = sp_OASetProperty @paramObj, 'Name', @Parameter1Name; IF @hr <> 0 GOTO OLE_ERROR; EXEC @hr = sp_OASetProperty @paramObj, 'Value', @Parameter1Value; IF @hr <> 0 GOTO OLE_ERROR; -- 将参数对象加入数组 EXEC @hr = sp_OASetProperty @paramArray, 'Item(0)', @paramObj; IF @hr <> 0 GOTO OLE_ERROR; -- 设置报表执行参数 EXEC @hr = sp_OAMethod @reportService, 'SetExecutionParameters', NULL, @paramArray, 'en-US'; IF @hr <> 0 GOTO OLE_ERROR; -- 渲染报表为PDF(参数顺序严格匹配官方定义) DECLARE @extension NVARCHAR(50), @mimeType NVARCHAR(50), @encoding NVARCHAR(50); DECLARE @warnings INT, @streamIDs INT; EXEC @hr = sp_OAMethod @reportService, 'Render', @reportBytes OUT, 'PDF', NULL, @extension OUT, @mimeType OUT, @encoding OUT, @warnings OUT, @streamIDs OUT; IF @hr <> 0 GOTO OLE_ERROR; -- 释放OLE对象 EXEC sp_OADestroy @paramObj; EXEC sp_OADestroy @paramArray; EXEC sp_OADestroy @reportService; -- 写入PDF文件(使用OPENROWSET避免动态SQL转换问题) DECLARE @sql NVARCHAR(MAX); SET @sql = N' INSERT INTO OPENROWSET(BULK ''' + REPLACE(@OutputFile, '''', '''''') + ''', SINGLE_BLOB) SELECT @FileBytes;'; EXEC sp_executesql @sql, N'@FileBytes VARBINARY(MAX)', @FileBytes = @reportBytes; RETURN; OLE_ERROR: -- 获取OLE错误信息 EXEC sp_OAGetErrorInfo @reportService, NULL, @errMsg OUT; RAISERROR('OLE操作错误: %s', 16, 1, @errMsg); -- 清理资源 IF @paramObj IS NOT NULL EXEC sp_OADestroy @paramObj; IF @paramArray IS NOT NULL EXEC sp_OADestroy @paramArray; IF @reportService IS NOT NULL EXEC sp_OADestroy @reportService; RETURN; END GO -- 执行示例 EXEC rsp_GenerateAndDeliverReports @ReportName='/All Reports/Subreports/07_sub', @Parameter1Name='ExportId', @Parameter1Value='2', @OutputFile='C:\Users\Public\Public Downloads\Report.pdf';
额外注意事项
- 确保SQL Server服务账户拥有目标路径的写入权限,否则即使代码正确也无法生成文件。
- 确认SSRS报表服务器URL正确,报表路径
@ReportName与服务器上的路径完全匹配(区分大小写)。 - 如果使用自定义的
sp_writebytesfile,需确保该存储过程能正确处理VARBINARY(MAX)数据并写入文件。
内容的提问来源于stack exchange,提问作者ToroShrey
相关产品推荐
相关产品推荐

