【问题标题】:How to split a large dataset into multiple Excel spreadsheets using an SSIS package?如何使用 SSIS 包将大型数据集拆分为多个 Excel 电子表格?
【发布时间】:2011-07-12 00:31:36
【问题描述】:

我遇到了一个 SSIS 包的问题。

  • 执行查询以从数据库(SQL Server 2008)(已执行数据流任务)
  • 使用 Excel Destination 将提取的数据导出到 Excel 97-2003 电子表格 (.xls)

众所周知,xls 文件的每张纸限制为 65,536 行 x 256 列。因此,当查询提取的记录数超过限制 (65,536) 时,Excel 目标步骤将失败。

我收到以下错误消息。

Error: 0xC0202009 at Calidad VIDA, Excel Destination [82]: SSIS Error Code DTS_E_OLEDBERROR. An OLE DB error has occurred. Error code: 0x80004005.

Error: 0xC0209029 at Calidad VIDA, Excel Destination [82]: SSIS Error Code DTS_E_INDUCEDTRANSFORMFAILUREONERROR. The "input "Excel Destination Input" (93)" failed because error code 0xC020907B occurred, and the error row disposition on "input "Excel Destination Input" (93)" specifies failure on error. An error occurred on the specified object of the specified component. There may be error messages posted before this with more information about the failure. Error: 0xC0047022 at Calidad VIDA, SSIS.Pipeline: SSIS Error Code DTS_E_PROCESSINPUTFAILED. The ProcessInput method on component "Excel Destination" (82) failed with error code 0xC0209029 while processing input "Excel Destination Input" (93). The identified component returned an error from the ProcessInput method. The error is specific to the component, but the error is fatal and will cause the Data Flow task to stop running. There may be error messages posted before this with more information about the failure.

Error: 0xC02020C4 at Calidad VIDA, OLE DB Source [1]: The attempt to add a row to the Data Flow task buffer failed with error code 0xC0047020.

Error: 0xC0047038 at Calidad VIDA, SSIS.Pipeline: SSIS Error Code DTS_E_PRIMEOUTPUTFAILED. The PrimeOutput method on component "OLE DB Source" (1) returned error code 0xC02020C4. The component returned a failure code when the pipeline engine called PrimeOutput(). The meaning of the failure code is defined by the component, but the error is fatal and the pipeline stopped executing. There may be error messages posted before this with more information about the failure.

该文件需要采用该格式,因为客户端没有较新的版本。他们不想购买许可证。有谁知道如何解决这个问题? 我应该使用脚本任务并自己制作 excel,还是应该为每个循环制作一个并创建各种 excel 工作簿?

【问题讨论】:

    标签: c# sql sql-server-2008 excel ssis


    【解决方案1】:

    这是一种可能的选项,您可以使用 SSIS 根据您希望在每个 Excel 工作表中写入的记录数来动态创建 Excel 工作表。这不涉及脚本任务。以下示例描述了如何使用执行 SQL 任务、For 循环容器和数据流任务来实现这一点。该示例是使用SSIS 2008 R2 创建的。

    分步过程:

    1. 在 SQL Server 数据库中,运行 SQL 脚本 部分下提供的脚本。这些脚本将创建一个名为dbo.SQLData 的表,然后使用从1 x 120 x 40 的乘法数据填充该表,从而创建800 记录。该脚本还会创建一个名为 dbo.FetchData 的存储过程,该过程将在 SSIS 包中使用。

    2. 在 SSIS 包上,创建 9 变量,如屏幕截图 #1 所示。以下步骤描述了如何配置这些变量。

    3. 将变量 ExcelSheetMaxRows 设置为值 80。此变量表示每个 Excel 工作表要写入的行数。您可以将其设置为您选择的值。在您的情况下,这将是 65,535(您可能希望为标题列名称保留 1 行)。

    4. 将变量 SQLFetchTotalRows 设置为值 SELECT COUNT(Id) AS TotalRows FROM dbo.SQLData。此变量包含从表中获取总行数的查询。

    5. 选择变量StartIndex,然后按F4 选择属性。将属性 EvaluateAsExpression 设置为 True,将属性 Expression 设置为值 (@[User::Loop] * @[User::ExcelSheetMaxRows]) + 1。请参阅屏幕截图 #2

    6. 选择变量EndIndex,然后按F4 选择属性。将属性 EvaluateAsExpression 设置为 True,将属性 Expression 设置为值 (@[User::Loop] + 1) * @[User::ExcelSheetMaxRows]。请参阅屏幕截图 #3

    7. 选择变量ExcelSheetName,然后按F4 选择属性。将属性 EvaluateAsExpression 设置为 True,将属性 Expression 设置为值 "Sheet" + (DT_WSTR,12) (@[User::Loop] + 1)。请参阅屏幕截图 #4

    8. 选择变量SQLFetchData,然后按F4 选择属性。将属性 EvaluateAsExpression 设置为 True,将属性 Expression 设置为值 "EXEC dbo.FetchData " + (DT_WSTR, 15) @[User::StartIndex] + "," + (DT_WSTR, 15) @[User::EndIndex]。请参阅屏幕截图 #5

    9. 选择变量ExcelTable,然后按F4 选择属性。将属性 EvaluateAsExpression 设置为 True,将属性 Expression 设置为 ExcelTable 变量值 部分下提供的值。请参阅屏幕截图 #6

    10. 在 SSIS 包的控制流选项卡上,放置一个执行 SQL 任务并按照屏幕截图 #7 和 #8 所示对其进行配置。此任务将获取记录数。

    11. 在 SSIS 包的控制流选项卡上,放置一个 For 循环容器并按照屏幕截图 #9 所示对其进行配置。请注意,这是 For 循环,而不是 Foreach 循环。此循环将根据要在每个 Excel 工作表中显示的记录数以及在表中找到的记录总数执行。

    12. 创建一个包含 .xls 扩展名的 Excel 97-2003 格式的 Excel 电子表格,如屏幕截图 #10 所示。我在 **C:\temp**

    13. 中创建了文件
    14. 在 SSIS 包的连接管理器上,创建一个名为 SQLServer 的指向 SQL Server 的 OLE DB 连接和一个名为 Excel 的指向新创建的 Excel 文件的 Excel 连接。

    15. 单击 Excel 连接并选择属性。将属性 DelayValidation 从 False 更改为 True,这样当我们在数据流任务中切换到使用变量创建工作表时,我们不会收到任何错误消息。请参阅屏幕截图 #11

    16. 在 For Loop 容器中,放置一个执行 SQL 任务并按照屏幕截图 #12 所示进行配置。此任务将根据要求创建 Excel 工作表。

    17. 在 For 循环容器内,放置一个数据流任务。配置任务后,“控制流”选项卡应如屏幕截图 #13 所示。

    18. 在数据流任务中,放置一个 OLE DB 源以使用存储过程从 SQL Server 读取数据。如屏幕截图 #14 和 #15 所示配置 OLE DB 源。

    19. 在数据流任务中,放置一个 Excel 目标以将数据插入 Excel 工作表。如屏幕截图 #16 和 #17 所示配置 Excel 目标。

    20. 配置数据流任务后,它应如屏幕截图 #18 所示。

    21. 删除步骤12中创建的Excel文件,因为包在执行时会自动创建文件。如果不删除,包会抛出Sheet1已经存在的异常。此示例使用路径 C:\temp\,屏幕截图 #19 显示该路径中没有文件。

    22. 屏幕截图 #20 和 #21 显示了控制流和数据流任务中的包执行情况。

    23. 屏幕截图 #22 显示文件 ExcelData.xls 已在路径 C:\temp 中创建。请记住,之前这条路径是空的。因为我们在表中有 800 行,我们设置包变量 ExcelSheetMaxRows 来为每张表创建 80 行。因此,Excel 文件有 10 张。请参阅屏幕截图 #23

    24. NOTE: 在此示例中我没有做的一件事是检查文件 ExcelData.xls 是否已存在于路径 C:\temp 中。如果存在,则应在执行任务之前删除该文件。这可以通过创建一个保存 Excel 文件路径的变量并使用文件系统任务在执行第一个执行 SQL 任务之前删除文件来实现。

    希望对您有所帮助。

    ExcelTable 变量值:

    "CREATE TABLE `" + @[User::ExcelSheetName] + "`(`Id` Long, `Number1` Long, `Number2` Long, `Value` Long)"
    

    SQL 脚本:

    --Create table
    
    CREATE TABLE [dbo].[SQLData](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [Number1] [int] NOT NULL,
        [Number2] [int] NOT NULL,
        [Value] [int] NOT NULL,
    CONSTRAINT [PK_Multiplication] PRIMARY KEY CLUSTERED ([Id] ASC)) ON [PRIMARY]
    GO
    
    --Populate table with data
    
    SET NOCOUNT ON
    
    DECLARE @OuterLoop INT
    DECLARE @InnerLoop INT
    SELECT @OuterLoop = 1
    
    WHILE @OuterLoop <= 20 BEGIN
    
        SELECT @InnerLoop = 1   
        WHILE @InnerLoop <= 40 BEGIN
    
                INSERT INTO dbo.SQLData (Number1, Number2, Value)
                VALUES (@OuterLoop, @InnerLoop, @OuterLoop * @InnerLoop)
    
                SET @InnerLoop = @InnerLoop + 1
        END
    
        SET @OuterLoop = @OuterLoop + 1
    END
    
    SET NOCOUNT OFF
    
    --Create stored procedure
    
    CREATE PROCEDURE [dbo].[FetchData]
    (
            @StartIndex INT
        ,   @EndIndex   INT
    )
    AS
    BEGIN
    
        SELECT  Id
            ,   Number1
            ,   Number2
            ,   Value
        FROM    (
                    SELECT  RANK() OVER(ORDER BY Id) AS RowNumber
                        ,   Id
                        ,   Number1
                        ,   Number2
                        ,   Value 
                    FROM    dbo.SQLData
                ) T1
        WHERE   RowNumber BETWEEN @StartIndex AND @EndIndex
    END
    GO
    

    屏幕截图 #1:

    屏幕截图 #2:

    截图#3:

    屏幕截图 #4:

    屏幕截图 #5:

    屏幕截图 #6:

    截图#7:

    截图#8:

    屏幕截图 #9:

    屏幕截图 #10:

    屏幕截图 #11:

    屏幕截图 #12:

    屏幕截图 #13:

    屏幕截图 #14:

    屏幕截图 #15:

    屏幕截图 #16:

    屏幕截图 #17:

    屏幕截图 #18:

    屏幕截图 #19:

    屏幕截图 #20:

    屏幕截图 #21:

    屏幕截图 #22:

    屏幕截图 #23:

    【讨论】:

      【解决方案2】:

      股票 excel 呈现选项允许将选项分页到单独的选项卡上。如果在适当的行数后强制分页,则输出中的每个“页面”都会有一个新选项卡。我没有过去为此使用的设置,但如果您需要,我可以在明天查找。

      【讨论】:

      • 谢谢,这将非常有帮助。我可以为此等待明天。我真的很感谢你的帮助。谢谢。
      • "在您的表格中,尝试创建一个没有页眉或页脚的组(在您拥有的任何当前分组之外),并将分页符设置为 true。对于分组值,使用表达式类似于 =ROWNUMBER(Nothing) MOD 60000 这应该在 60000 行数据后强制分页,导出时将转换为新的 Excel 选项卡。我相信 Excel 中的 65K 限制是基于每个工作表的。“跨度>
      • 以上引用来自以下位置:sqlservercentral.com/Forums/Topic632795-1063-1.aspx
      【解决方案3】:

      对我也有用的是使用 SSIS 包导出到 CSV 文件,然后手动将数据导入 Excel。请注意,这与 Excel 中的“打开”不同,因为它也只会停在 65536 行。创建一个新的 xlsx 文件并单击“数据”->“来自文本”。它将导入并显示所有行。测试了 750,000 行。

      但是,不确定 csv -> xlsx 转换是否可以轻松地在 SSIS 包中编写脚本。很可能通过使用 Excel COM 对象的脚本任务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-17
        • 2014-10-13
        • 2011-12-14
        相关资源
        最近更新 更多