在不知道工作表名称的情况下使用 SSIS 从 Excel 导入数据

Posted

技术标签:

【中文标题】在不知道工作表名称的情况下使用 SSIS 从 Excel 导入数据【英文标题】:Import data from Excel using SSIS without knowing sheet name 【发布时间】:2010-12-14 20:58:20 【问题描述】:

我有一个由另一台服务器更新的电子表格(我无法控制),我需要自动将该数据导入 SQL 2005。数据始终是电子表格的第一页。但是,该工作表的名称会根据行数而变化。

有没有办法在事先不知道工作表名称的情况下运行从 Excel 中提取数据的 SSIS 作业?它似乎依赖工作表名称作为数据源,但我希望告诉它“工作表编号 1”或类似的东西。

【问题讨论】:

能否查询Excel文件中的“表格”(工作表),然后只使用第一个? 好主意,但知道该怎么做吗? 【参考方案1】:

我会将工作表名称编写成 SSIS 用户变量。如果你不反对在你的 SSIS 包中插入一个脚本任务试试这个:(基于link text)

Excel.Application xlApp = new Excel.ApplicationClass();
Excel.Workbook xlWorkBook = xlApp.Workbooks.Open("<Name of your excel app>.xls", 0, xlWorkBook true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
// Look up worksheet by index
Excel.Worksheet xlWorkSheet =(Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

user::worksheetname = xlWorkSheet.Name;

/* Do clean up.  Working with COM object */

【讨论】:

在我看来这是最好的选择,如果我不得不再次解决这个问题,我会先尝试这条路线。谢谢阿达玛!不过,我正在工作的项目已经使用了 UI 自动化,所以我最终只是附加了一个脚本来自动更改名称。 更新:我在这里找到了我的 Excel 参考:C:\Program Files (x86)\Microsoft Visual Studio 11.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Excel.dll .如何获得对“Excel.Application”的引用?我需要添加 DLL 引用吗?我正在运行安装了“Microsoft Access Database Engine 2010 Redistributable”的 64 位 Excel,以允许我在 SSIS 中使用 Excel 源代码。 上面代码中的 Open 方法中似乎还有一个杂散的“xlWorkBook”值。【参考方案2】:

仅作记录,我在脚本任务中使用此代码来解决问题。使用的变量有:文件名SheetName

请注意,我的 Excel 文件名是动态的。

// GET NAME OF FIRST SHEET
string filename = (string)Dts.Variables["Filename"].Value;
string sheetName = null;

string connStr =
    String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=0;Extended Properties=\"EXCEL 8.0;IMEX=1;\"", filename);

var conn = new OleDbConnection(connStr);
try 
           
    conn.Open();

    using(var dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null))
    
        var row0 = dtSheet.Rows[0];
        sheetName = row0["TABLE_NAME"].ToString();
    

catch (Exception)

    throw;

finally

    conn.Close();
    conn.Dispose();


if (!String.IsNullOrEmpty(sheetName))

    Dts.Variables["SheetName"].Value = sheetName;
    Dts.Events.FireInformation(1, "User::SheetName", sheetName, "", 0, ref dummy);
    Dts.TaskResult = (int)ScriptResults.Success;

else

    Dts.Events.FireError(0, "User::SheetName", "No SheetName found!", String.Empty, 0);
    Dts.TaskResult = (int)ScriptResults.Failure;

【讨论】:

【参考方案3】:

我遇到了类似的问题。我实现的解决方案是首先使用 OleDB 连接读取 excel 文件。打开连接,然后检索所有工作表名称。这是一个例子

Dim strConnectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\ABC.xls;Extended Properties=""EXCEL 8.0;"""

Dim lstSheetName As List(Of String) = Nothing
Try
 objConn = New OleDbConnection(Me.ConnectionString)
 objConn.Open()
 lstSheetName = New List(Of String)
 Using dtSheetTable As DataTable =       objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,Nothing)

  For Each drRow As DataRow In dtSheetTable.Rows
     lstSheetName.Add("[" & drRow("TABLE_NAME").ToString().Replace("'", "''") & "]")
  Next
 End Using
Catch ex as Exception
 Throw
Finally
 If objConn.State = ConnectionState.Open Then objConn.Close()
 objConn.Dispose()
End Try

所有代码都是用 ASPX.VB 编写的,然后我通过后面的代码执行 SSIS 包,并在 lstSheetName 变量 (lstSheetName(0).ToString()) 中传递第一个值

这是

【讨论】:

【参考方案4】:

如果有人在使用 JET 驱动程序时遇到问题,您现在可以使用 AccessDatabase 驱动程序。这是从上面改编的,并且经过验证可以在我的机器上运行,不需要额外的参考。

using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Data.OleDb;

    public void Main()
    
        // GET NAME OF FIRST SHEET
        string filename = Dts.Variables["User::ActiveFileName"].Value.ToString();
        string sheetName = null;
        bool dummy = true;

        string connStr =
            String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=0;Extended Properties=\"EXCEL 12.0 XML;HDR=YES\";", filename);
        var conn = new OleDbConnection(connStr);
        try
        
            conn.Open();

            using(var dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null))
            
                var row0 = dtSheet.Rows[0];
                sheetName = row0["TABLE_NAME"].ToString();
            

            if (!String.IsNullOrEmpty(sheetName))
            
                Dts.Variables["SheetName"].Value = sheetName;
                Dts.Events.FireInformation(1, "User::SheetName", sheetName, "", 0, ref dummy);
                Dts.TaskResult = (int)ScriptResults.Success;
            
            else
            
                throw new Exception("No SheetName found!");
            
        
        catch (Exception ex)
        
            Dts.Events.FireError(0, "User::SheetName", ex.Message, String.Empty, 0);
            Dts.TaskResult = (int)ScriptResults.Failure;
        
        finally
        
            conn.Close();
            conn.Dispose();
        
    

【讨论】:

【参考方案5】:

我不这么认为...我不知道任何可以使用的序数引用语法,例如 Sheets[0]。

因此,如果您在不知道工作表名称的情况下无法获取数据 - 您只需要动态找出工作表名称即可。 getting Excel schema info in SSIS 上的这个链接应该可以帮助你做到这一点。一旦你有了它,你就可以将工作表名称作为变量传递,然后就可以走了。

【讨论】:

【参考方案6】:

我自己过去也遇到过同样的问题,并且无法找到解决方案来读取 Excel 文件,该文件的工作表名称会因文件而异。

我无法开始工作的猜测是在数据连接的属性中使用表达式。您需要以某种方式将工作表名称读入变量,然后将该变量的结果用于数据连接的工作表名称。

祝你好运,很抱歉我无法提供更多帮助。

【讨论】:

以上是关于在不知道工作表名称的情况下使用 SSIS 从 Excel 导入数据的主要内容,如果未能解决你的问题,请参考以下文章

是否可以从SSIS源动态创建表

有没有办法在不写查询中所有字段名称的情况下选择第一个表?

在不了解文化的情况下将月份名称从一种语言转换为另一种语言?

如何在不知道名称的情况下访问结构成员?

在不知道对象索引的情况下从数组中删除对象?

如何在不知道子类名称的情况下访问 django 中对象的子类?