通过SSIS将带有动态名称的Excel文件导入SQL表?

时间:2013-09-05 15:13:23

标签: sql-server excel ssis

我在这里做了一些搜索,虽然有些问题是similar,但它们似乎并不是我需要的。

我要做的是通过SSIS将Excel文件导入SQL表,但问题是我永远不会知道确切的文件名。我们没有稳定的间隔获取文件,文件通常在名称中有一个日期/月份。例如,我们当前的文件是“Census Data - May 2013.xls”。我们一次只能加载一个文件,因此我不需要遍历多个Excel文件的目录。

我的概念是我可以获取此文件,将其复制到“加载”目录,然后从那里加载它。在程序包开始时,我将首先清除加载目录,然后扫描原始目录中的Excel文件,将其复制到加载目录,然后将其加载到SQL中。我想我可能必须将文件名存储在某处,所以我不会在随后的几个月内将相同的文件复制到加载目录中,但我不确定处理它的最佳方法。

除了扫描目录中的Excel文件并将其复制到加载目录之外,我几乎已经完成了所有工作。我从this page获取了大部分信息,这些信息(再次)接近我想要做的但不完全是我需要的解决方案。

有人能让我超越终点吗?我似乎无法正确使用Excel连接管理器(这是我第一次使用变量),我无法弄清楚如何将文件放入Loading目录。

1 个答案:

答案 0 :(得分:8)

问题陈述

如何动态识别文件名?

您需要一些机制来检查文件夹的内容并查看存在的内容。具体来说,您正在寻找" Loading"中的Excel文件。目录。你知道文件扩展名就是这样。

决议A

使用ForEach文件枚举器。

使用FileSpec *.xls*.xlsx上的表达式配置枚举器,具体取决于您正在处理的Excel的风格。

Directory上添加另一个表达式作为您的加载目录。

我通常创建名为FolderInputFileMask的SSIS变量,并在枚举器中分配这些变量。

enter image description here

现在,当您运行包时,Enumerator将查找Diretory并查找与FileSpec匹配的所有文件。

需要用找到的东西完成。您需要使用Enumerator返回的文件名。这是通过Variable Mappings选项卡完成的。我创建了一个名为CurrentFileName的第三个变量,并为其分配了枚举器的结果。

enter image description here

如果您将一个脚本任务放在ForEach枚举器中,您应该能够看到" Locals"中的值。 @ [User :: CurrentFileName]的窗口已从 的设计时间值更新为" real"文件名。

决议B

使用脚本任务。

您仍然需要创建一个变量来保存当前文件名,并且可能还有一个可用的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答案中称呼它。