【发布时间】:2016-05-27 21:03:39
【问题描述】:
我收到一个每月需要使用 SSIS 包导入 SQL Server 的 XLSX 文件。不幸的是,发件人不遵循文件名或工作表的 UNC 命名,而且我们最近迁移到 SQL Server 2012 导致包失败 - 即使使用 Excel 连接管理器也是如此。我们也尝试过向他们发送模板,但他们拒绝遵循,我们也无法强迫他们这样做。
我一直在尝试对包进行更新,该更新将使用脚本任务将两个 Excel 工作表中的每一个导入到 System.Object 中,然后我可以查询或循环将数据导入目标 SQL Server 表。
到目前为止,使用 Microsoft here 的示例,我已经成功地将 Excel 文件路径/名称以及两个工作表名称导入到对象变量中。但是,这不会创建包含来自任一工作表的实际数据集的对象。
根据此处和网络上其他地方的示例,我已经启动了一个 C# 脚本,我相信它会将工作表数据输出到一个 Object 变量中,但是我对 C# 不是很精通,并且很难在没有要复制的完整示例。到目前为止,这是我的代码:
using System;
using System.Data;
using System.Data.OleDb;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public DataSet Main()
{
string fileName;
string connectionString;
fileName = Dts.Variables["ExcelFile"].Value.ToString();
Console.WriteLine(fileName);
connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=" + fileName + ";Extended Properties=Excel 12.0 Xml";
Console.WriteLine(connectionString);
DataSet data = new DataSet();
using (OleDbConnection con = new OleDbConnection(connectionString))
{
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM [Sheet1$]", connectionString);
adapter.Fill(data);
}
return data;
}
}
代码构建成功,但是当我运行包时收到一个无法描述的错误
错误:脚本任务中的 0x1:调用的目标已引发异常。
任务失败:脚本任务
我的任何一个Console.WriteLine 命令都没有得到任何输出,所以我相信脚本任务会立即失败。我确实有延迟验证 = True,尽管更改它并没有什么不同。您在我的脚本中看到任何明显/新手错误吗?我已经使用 SQL 和 SSIS 多年,但我的 C#/VB/Java/etc.知识和经验有限。
另外,如果我忽略了在 SSIS 中完成此任务的更好方法(Excel 连接除外,它不起作用),请告诉我。
更新 - 2016 年 5 月 31 日:我认为我今天有一点时间来处理这个项目,并且取得了一些进展。我更新了我的脚本任务以包括以下内容:
DataSet data = new DataSet();
using (OleDbConnection con = new OleDbConnection(connectionString))
{
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
//OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM [Indemnity Scores$]", con);
adapter.Fill(data);
Dts.Variables["ExcelDataTable_IndemnityScores"].Value = data;
}
脚本任务现在成功完成,所以我后来添加了一个 Foreach 循环容器,将其设置为 Foreach From Variable Enumerator,并选择 ExcelDataTable_IndemnityScores 作为集合。
但是,现在我很难从这个 Object 变量中提取数据。它有(或至少应该有)两列,我在变量映射中设置,并且正在使用执行 SQL 命令将值插入到表中。不幸的是,每列只插入一个空白值。
接下来我将执行 SQL 替换为一个简单的脚本任务,以返回每个变量的值。不幸的是,它返回的不是值,而是“Microsoft.SqlServer.Dts.Runtime.Variable”。我认为这是我的新手错误,但我还没有在网上找到任何解释该错误的信息?
2016 年 6 月 14 日更新: 我终于完成了这个包,它昨天在生产中成功运行。我最终使用了此处提供的建议以及其他地方的示例。我的一般工作流程需要三重嵌套的 Foreach 循环来获取从源工作簿导入的两个工作表 - 我只希望每月一个,但没有 100% 符合此任务。
我最外层的循环只是枚举我的导入目录以查找 FTP 进程下载的文件。它包含两个脚本任务。第一个只是确认 FTP 进程下载的第一个电子表格的文件名。我将上面的 Microsoft 链接用于我的代码,只对我的变量名进行了少量修改。
第二个任务从第一个电子表格中获取所有工作表名称,并且也是使用上面的 Microsoft 链接构建的。但是,我排除了任何带有“#”的工作表名称,以防止将 XML 数据库分配给我的变量。
第二个循环(第一个内部循环)枚举在第一个循环中解析的每个工作表名称。它包含三个脚本任务,第一个任务将数据从第一个工作表导入到我的对象变量中。
public void Main() { 尝试 {
string fileName;
string connectionString;
string worksheetName;
string query;
fileName = Dts.Variables["ExcelFile"].Value.ToString();
//MessageBox.Show("InsertWorksheetDataIntoObject - Filename: " + fileName);
connectionString = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source={0};Extended Properties=Excel 12.0 Xml;", fileName);
//MessageBox.Show("Connection: " + connectionString);
worksheetName = Dts.Variables["ExcelTable"].Value.ToString();
worksheetName = worksheetName.Replace("'", "");
//MessageBox.Show("InsertWorksheetDataIntoObject - Worksheet: " + worksheetName);
query = string.Format("SELECT * FROM [" + worksheetName + "]");
//MessageBox.Show("Query: " + query);
DataSet data = new DataSet();
using (OleDbConnection con = new OleDbConnection(connectionString))
{
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
adapter.Fill(data);
Dts.Variables["ExcelDataTable"].Value = data;
}
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception ex)
{
Dts.Events.FireError(-1, "ErrorMessage", ex.ToString(), "", 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
//return data;
}
此循环中的第二个脚本任务只是从 Excel 中删除所有空白行。我本可以将它与上面的脚本合并,但我保留了它的便携性,以便将来在其他地方重用。
此循环中的第三个脚本任务使用工作表名称设置一个变量,该变量在下一个循环中用于确定我的目标表。
第三个循环(第二个内部循环)枚举包含工作表数据的对象变量中的行。它包含一个执行 SQL 任务,该任务根据上面工作表名称设置的变量值将来自两个源列的数据导入到正确的目标表中。由于工作表名称并不总是一致的,因此此循环直接连接到我的对象变量,这样就无需按名称调用源列。相反,我只是将每个变量分配给 Foreach 循环中的目标变量,然后将这些数据逐行传递到我的表中。
再次感谢大家的帮助和建议!
【问题讨论】:
-
您是否尝试过启用此excel-sql-server.com/…(临时、动态参数、允许进行中等)并在 SSMS 中从该文件中获取数据?
标签: c# sql-server excel ssis ssis-2012