3

给定 SQL Server 中的一张表,其中包含来自三个源表的合并数据,其中包括一列称为 OFFICE 的列,用于区分记录。

这三个源表包含来自三个办公室的数据。

我想动态创建一个 Excel 文件,该文件将根据三个不同的办公室(例如 office1、office2、office3)在一个工作簿中包含 3 张工作表,从而使每张工作表都包含根据其办公室的相关数据。

请推荐一种在 SSIS 中使用动态 Excel 目标的方法,因为我不想使用创建模板文件然后将该模板复制到目标 Excel 文件的方法。

4

2 回答 2

2

虽然这可以使用 scipt 任务和 C# 来完成,但在 http://www.rafael-salas.com/2006/12/import-header-line-tables-_116683388696570741.html上演示了一个更简单的解决方案

和后续

http://www.rafael-salas.com/2008/03/ssis-and-dynamic-excel-destinations_01.html#!

但要总结相关细节,您需要使用“执行 SQL 任务”在运行时动态创建工作表,然后再将其用作目标。

创建一个新变量来保存工作表名称,并在迭代它们时将此变量设置为您正在使用的 Office。

此外,创建一个变量来保存将创建每个工作表的 Create table 语句。例如,

“创建表"+ @[User::SheetName] + "HeaderID整数,HeaderNameNVARCHAR(50),LineID整数,LineNameNVARCHAR(50),LineDetailsNVARCHAR(50))”

并将 For Each 容器内的 Execute SQL 任务的 SQLSourceType 属性设置为变量,然后选择您创建的变量来保存创建语句。

在 Excel 目标组件中,将数据访问模式更改为“表名称或视图名称变量”,然后从变量下拉列表中选择您创建的工作表名称变量。

于 2013-11-11T18:19:48.430 回答
0

我有几个执行类似功能的 SSIS 包。单个 Excel 文件由多个工作表组成,每个工作表由单独的 SQL 查询的结果填充。这是我应用的基本通用步骤。在开始之前,请确保为要应用的数据库和输出 Excel 文件创建一个连接管理器。

1)在控制流中创建一个脚本任务并像下面这样填充它。在这里,我正在创建 Excel 文件以及它将包含的工作表。(工作表不应该包含任何空格或特殊字符。)我下面的代码是在 C# 中。

using System;
using System.IO;
using System.Collections.Generic;
using System.Data;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.SqlServer.Dts.Runtime;

namespace ST_87e8d62a054b4e16b60297154afc19d8.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{

    #region VSTA generated code
    enum ScriptResults
    {
        Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
        Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
    };
    #endregion

    public void Main()
    {
        Excel.Application xlApp;
        Excel.Workbook xlWorkBook;
        Excel.Worksheet xlWorkSheet;
        object misValue = System.Reflection.Missing.Value;

        xlApp = new Excel.ApplicationClass();
        xlWorkBook = xlApp.Workbooks.Add(misValue);

        //Create First worksheet
        xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
        xlWorkSheet.Name = "Names";

        //Define column headers for "RawData" WorkSheet
        xlWorkSheet.Cells[1, 1] = "First Name";
        xlWorkSheet.Cells[1, 2] = "Last Name";
        xlWorkSheet.Cells[1, 3] = "Title";

        // Create Second Worksheet
        xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(2);
        xlWorkSheet.Name = "Addresses";

        //Define column headers for "CCDN" WorkSheet
        xlWorkSheet.Cells[1, 1] = "Street";
        xlWorkSheet.Cells[1, 2] = "City";
        xlWorkSheet.Cells[1, 3] = "State";
        xlWorkSheet.Cells[1, 4] = "Zip";
        xlWorkSheet.Cells[1, 5] = "Country";

        string Filename = "C:\\MyFile.xls";


        if (File.Exists(Filename))
        {
            File.Delete(Filename);
        }


        xlWorkBook.SaveAs(Filename, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
        xlWorkBook.Close(true, misValue, misValue);
        xlApp.Quit();

        releaseObject(xlWorkSheet);
        releaseObject(xlWorkBook);
        releaseObject(xlApp);


        Dts.TaskResult = (int)ScriptResults.Success;
    }

2) 在您的数据库中创建两个将临时填充的表。也就是说,将为第一个工作表的结果填充一个表,为第二个工作表的结果填充第二个表。在每个表的名称前加上“Working_”是一种很好的命名方法,以便您了解每个表的用途。我采用使用表而不是视图的方法是因为我喜欢对我的结果进行排序(ORDER BY),而这不能用视图来完成。

3) 在 SSIS 包中添加 Control Flow 下的两个 Execute SQL Tasks。第一个任务将运行一个 INSERT SQL 语句,该语句将填充您刚刚创建的第一个表,第二个任务将运行另一个 INSERT SQL 语句,该语句将填充刚刚创建的第二个表。

4)在SSIS包中添加Control Flow下的两个Data Flow任务。第一个用于填充第一个工作表,第二个用于填充第二个工作表。

5) 选择第一个数据流任务并在数据流下添加一个 OLE DB 源,您将在其中定义 OLE DB 连接管理器(您的数据库),然后是表或视图。选择创建的第一个新表。确保选择了所有感兴趣的列并且您可以执行预览。

6) 添加数据转换流任务,然后添加 Excel 目标流任务。

7) 对第二个工作表和表格重复步骤 5 和 6。

8) 最后在控制流下添加一个 Excel SQL 任务,它将删除两个工作表的内容。您不希望在下次运行包时包含旧内容。

现在,如果您想在 Excel 文件完成后对其进行格式化并给您的经理留下深刻印象,您也可以使用最终任务脚本(也使用 C#)在代码中执行此操作。这种方法的好处是您不必在 SQL 中应用任何特殊的格式化函数,Excel 可以完成所有工作。您实际上可以在步骤 1 中包含格式,并且一旦您在以下步骤中复制数据,它就会自动格式化。与任何报告输出一样,当让 Excel 或 SSRS 做它们最擅长的事情更有效时,让 SQL 执行格式化步骤(向数据库服务器添加额外的工作)是没有意义的。

        public void Main()
    {
        Excel.Application xlApp;
        Excel.Workbook xlWorkBook;
        Excel.Worksheet xlWorkSheet;
        object misValue = System.Reflection.Missing.Value;
        Excel.Range xlRange;

        xlApp = new Excel.ApplicationClass();
        string Filename = "C:\\MyFile.xls";
        xlWorkBook = xlApp.Workbooks.Open(FileName, 0, false, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);

        //Format cells in Names worksheet
        xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

        //Set the header range in bold font
        xlRange = xlWorkSheet.get_Range("a1", "p1");
        xlRange.Font.Bold = true;
        xlRange.WrapText = true;

        //Freeze first row listing headers
        xlWorkSheet.Application.ActiveWindow.SplitRow = 1;
        xlWorkSheet.Application.ActiveWindow.FreezePanes = true;

        //Auto adjust the width of each column
        xlWorkSheet.Columns.AutoFit();

        xlRange = xlWorkSheet.get_Range("c1", "j6467");
        xlRange.Cells.Locked = false;
        xlRange.Interior.Color = 65535;

        xlRange = xlWorkSheet.get_Range("o1", "p6467");
        xlRange.Cells.Locked = false;
        xlRange.Interior.Color = 65535;

        //Do not alert when saving changes to Excel file.
        xlWorkBook.Application.DisplayAlerts = false;

        //Save Excel file modifications
        xlWorkBook.Save();

        //Close workbook and application
        xlWorkBook.Close(true, misValue, misValue);
        xlApp.Quit();

        //Release from cache.
        releaseObject(xlWorkSheet);
        releaseObject(xlWorkBook);
        releaseObject(xlApp);

        //Set formatting of percent cells
        xlRange = xlWorkSheet.get_Range("d3", "d7");
        xlRange.NumberFormat = "###,###%";

      //Define the top left cell and bottom right cell of the table in the Excel worksheet
        xlRange = xlWorkSheet.get_Range("c1", "c7");

        //Draw grid of thin line around each cell in table
        xlRange.BorderAround(Excel.XlLineStyle.xlContinuous, Excel.XlBorderWeight.xlThin, Excel.XlColorIndex.xlColorIndexAutomatic, 1);

        //Draw thick border around entire table
        xlRange = xlWorkSheet.get_Range("a1", "d7");
        xlRange.BorderAround(Excel.XlLineStyle.xlContinuous, Excel.XlBorderWeight.xlThick, Excel.XlColorIndex.xlColorIndexAutomatic, 1);


        //Right justify columns B and C
        xlRange = xlWorkSheet.get_Range("b3", "c7");
        xlRange.HorizontalAlignment = Excel.XlHAlign.xlHAlignRight;



        //Do not alert when saving changes to Excel file.
        xlWorkBook.Application.DisplayAlerts = false;

        //Save Excel file modifications
        xlWorkBook.Save();

        //Close workbook and application
        xlWorkBook.Close(true, misValue, misValue);
        xlApp.Quit();

        //Release from cache.
        releaseObject(xlWorkSheet);
        releaseObject(xlWorkBook);
        releaseObject(xlApp);


        Dts.TaskResult = (int)ScriptResults.Success;
    }

就是这样。请注意,仅出于本示例的目的,我对文件名进行了硬编码。但在我的实际代码中,我应用了一个用户变量,然后由另一个 SQL 语句从另一个数据库表中提取名称来填充该变量。对于最佳实践,让您的 SSIS 包完全由表驱动是一个好主意。这样,对名称和位置所做的任何更改都将在特定于您的 SSIS 包的记录中的数据库表中进行...避免任何需要更新您的 SSIS 包并再次通过开发到质量保证再到生产生命周期。

希望这会有所帮助,如果您有任何问题,请告诉我。

于 2013-03-28T00:38:01.010 回答