You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过存储过程从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 20:43:16