我在这里做了一些搜索,虽然有些问题是similar,但它们似乎并不是我需要的。
我要做的是通过SSIS将Excel文件导入SQL表,但问题是我永远不会知道确切的文件名。我们没有稳定的间隔获取文件,文件通常在名称中有一个日期/月份。例如,我们当前的文件是“Census Data - May 2013.xls”。我们一次只能加载一个文件,因此我不需要遍历多个Excel文件的目录。
我的概念是我可以获取此文件,将其复制到“加载”目录,然后从那里加载它。在程序包开始时,我将首先清除加载目录,然后扫描原始目录中的Excel文件,将其复制到加载目录,然后将其加载到SQL中。我想我可能必须将文件名存储在某处,所以我不会在随后的几个月内将相同的文件复制到加载目录中,但我不确定处理它的最佳方法。
除了扫描目录中的Excel文件并将其复制到加载目录之外,我几乎已经完成了所有工作。我从this page获取了大部分信息,这些信息(再次)接近我想要做的但不完全是我需要的解决方案。
有人能让我超越终点吗?我似乎无法正确使用Excel连接管理器(这是我第一次使用变量),我无法弄清楚如何将文件放入Loading目录。
答案 0 :(得分:8)
如何动态识别文件名?
您需要一些机制来检查文件夹的内容并查看存在的内容。具体来说,您正在寻找" Loading"中的Excel文件。目录。你知道文件扩展名就是这样。
使用ForEach文件枚举器。
使用FileSpec
*.xls
或*.xlsx
上的表达式配置枚举器,具体取决于您正在处理的Excel的风格。
在Directory
上添加另一个表达式作为您的加载目录。
我通常创建名为FolderInput
和FileMask
的SSIS变量,并在枚举器中分配这些变量。
现在,当您运行包时,Enumerator将查找Diretory并查找与FileSpec匹配的所有文件。
需要用找到的东西完成。您需要使用Enumerator返回的文件名。这是通过Variable Mappings选项卡完成的。我创建了一个名为CurrentFileName的第三个变量,并为其分配了枚举器的结果。
如果您将一个脚本任务放在ForEach枚举器中,您应该能够看到" Locals"中的值。 @ [User :: CurrentFileName]的窗口已从 的设计时间值更新为" real"文件名。
使用脚本任务。
您仍然需要创建一个变量来保存当前文件名,并且可能还有一个可用的FolderInput和FileMask变量。将前者设置为ReadWrite,将后者设置为ReadOnly变量。
选择您选择的.NET语言。我正在使用C#。方法System.IO.Directory.EnumerateFiles
using System;
using System.Data;
using System.IO;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
namespace ST_fe2ea536a97842b1a760b271f190721e
{
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
string folderInput = Dts.Variables["User::FolderInput"].Value.ToString();
string fileMask = Dts.Variables["User::FileMask"].Value.ToString();
try
{
var files = Directory.EnumerateFiles(folderInput, fileMask, SearchOption.AllDirectories);
foreach (string currentFile in files)
{
Dts.Variables["User::CurrentFileName"].Value = currentFile;
break;
}
}
catch (Exception e)
{
Dts.Events.FireError(0, "Script overkill", e.ToString(), string.Empty, 0);
}
Dts.TaskResult = (int)ScriptResults.Success;
}
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
}
}
鉴于针对上述问题的两个解决方案,您如何选择?通常,人们说"它取决于"但 依赖的唯一时间是,如果在Loading文件夹中存在多个文件 的情况下进程应该停止/错误输出。这就是ForEach枚举器比脚本任务更麻烦的情况。否则,正如我在最初的回复中所述,这会增加您的开发,测试和维护项目的成本,但没有明显的收益。
进一步解决问题中的细微差别:配置Excel - 您需要更加具体地了解不起作用的内容。 Siva的SO答案和链接的blogspot文章都展示了如何使用我调用CurrentFileName
的变量的值来确保Excel文件指向"右边"文件。
对于Connection Manager和数据流,您需要将DelayValidation
设置为True,因为当包开始执行时,Variable的设计时值将无效。看到这个answer for a longer explanation但是,再一次,Siva在他们的SO答案中称呼它。