防止平面文件目标中的重复标题 - SSIS

Posted

技术标签:

【中文标题】防止平面文件目标中的重复标题 - SSIS【英文标题】:Prevent Duplicate headers in flat file destination - SSIS 【发布时间】:2013-05-05 12:08:31 【问题描述】:

我需要一些帮助。

我正在从 oledb 源导入 .csv 文件中的一些数据。我不希望标题在目的地出现两次。如果我取消选中“第一个数据行中的列名”属性,则标题也不会在第一次执行中填充。

截至目前的输出。

Col1,Col2
A,B
Col1,Col2
C,D

如何使包以这样的方式运行,如果文件为空,则插入标头。然后如果再次执行,则不包含标头,仅包含数据。

有一个类似的线程,但无法将解决方案应用为如何使用表达式来获取目标本身的行数。很久以前了,所以我创建了一个新的。

非常感谢您的帮助。

-阿克谢

【问题讨论】:

您有一个现有的表。您想加载源文件中的所有数据,第一次加载时包含的列。在后续加载时,不要将列名添加回表中吗?我对将列名与实际数据一起存储的价值感到困惑。 我正在从我的源数据库加载数据。想要将其插入到 .CSV 文件中。假设包将第一次运行。如果数据在 SQL 表中,则创建一个文件并插入数据(完成)。如果我再次运行包,我不希望将 HEADERS (COL1,COL2,COL3) 作为数据附加到文件中,而是将数据附加到文件中。我希望现在这更有意义。 【参考方案1】:

也许我遗漏了一些东西,但这对我有用。我没有 ColumnNamesInFirstDataRow 的只读问题

我创建了一个名为AddHeader 的包级变量,键入布尔值并将其设置为True。我添加了一个名为 FFCM 的平面文件连接管理器,并将其配置为使用 2 列 HeadCount (int)、AddHeader (boolean) 的 CSV 输出。在连接管理器的属性中,我为属性“ColumnNamesInFirstDataRow”添加了一个表达式,并为其分配了一个值@[User::AddHeader]

我添加了一个脚本任务来测试文件的大小。它具有对变量 AddHeader 的读/写访问权限。然后我使用这个脚本来确定文件是否为空。如果您对“空”的定义是它有一个标题行,那么我会调整 if 检查中的逻辑以匹配该长度。

    public void Main()
    

        string path = Dts.Connections["FFCM"].ConnectionString;

        System.IO.FileInfo stats = null;
        try
        
            stats = new System.IO.FileInfo(path);
            // checking length isn't bulletproof based on how the disk is configured
            // but should be good enough
            // http://***.com/questions/3750590/get-size-of-file-on-disk
            if (stats != null && stats.Length != 0)
            
                this.Dts.Variables["AddHeader"].Value = false;
            
        
        catch
        
            // no harm, no foul
        
        Dts.TaskResult = (int)ScriptResults.Success;
    

我循环了两次以确保生成附加场景

我删除了我的文件并运行了包,但只有一次标题。

【讨论】:

感谢您的解决方案。我确实实现了它。【参考方案2】:

控制列名是否包含在输出文件中的属性是 ColumnNamesInFirstDataRow。这是一个只读属性。

实现您想要做的事情的一种方法是在控制流表面上有两个数据流任务,然后是一个脚本任务。这两个数据流任务将是相同的,只是它们将引用两个不同的平面文件连接管理器。同样,这两者之间的唯一区别是 ColumnsInTheFirstDataRow 的不同值;一个是真的,另一个是假的。

使用此脚本任务来决定这是第一次运行还是后续运行。保留此信息并在脚本中检查它。您可以为这些信息创建一个单独的表,或者使用一些日志表来推断它。

【讨论】:

【参考方案3】:

以下解决方案对我有用。您也可以尝试以下解决方案。

    创建三个变量。

IsHeaderRequired RowCount TargetFilePath

    使用执行 SQL 任务获取源行计数并将其保存在 RowCount 变量。 有脚本任务。添加只读变量TargetFilePathRowCount。添加读写变量IsHeaderRequired

    编辑脚本并添加以下代码行。

        string targetFilePath = Dts.Variables["TargetFilePath"].Value.ToString();
        int rowCount = (int)Dts.Variables["RowCount"].Value;
    
        System.IO.FileInfo targetFileInfo = new System.IO.FileInfo(targetFilePath);
    
        if (rowCount > 0)
        
            if (targetFileInfo.Length == 0)
            
                Dts.Variables["IsHeaderRequired"].Value = true;
            
            else
            
                Dts.Variables["IsHeaderRequired"].Value = false;
            
        
    
        Dts.TaskResult = (int)ScriptResults.Success;
    

    将脚本组件连接到数据库

    点击平面文件的连接管理器[即你的目标文件]然后去 到属性。在表达式中,提及以下内容,如图所示 截图。

    Map the connectionString to variable "TargetFilePath".
    Map the ColumnNamesInFirstDataRow to "IsHeaderRequired".
    

平面文件连接管理器的表达式。

最终包装[截图]:

希望对你有帮助

【讨论】:

该解决方案效果很好,但我希望知道一些不需要检查文件详细信息的额外任务(脚本任务 n 全部)。不过,您的解决方案值得赞赏。【参考方案4】:

解决方案 ....

首先,在 Foreach 循环或更高的范围内添加一个 SSIS 整数变量 - 我将调用此 RowCount - 并将其默认值设为负(这很重要!)。接下来,将 Row Count 添加到您的数据流中,并将结果分配给我们刚刚创建的 RowCount SSIS 变量。第三,选择您的连接管理器(不要双击)并打开属性窗口 (F4)。找到 Expressions 属性,选择它,然后点击省略号 (...) 按钮。选择 ColumnNamesInFirstDataRow 属性,并使用如下表达式:

[@User::RowCount]

现在,当您的包启动时,RowCount 的静态值是 -1 或另一个负数。当数据流在循环中首次启动时,ColumnNamesInFirstDataRow 属性的值为 TRUE。当第一个数据流完成时,行计数(即使它为零)被写入 RowCount 变量。在循环的第二次交互中,连接管理器被重新配置为不写入列名...


【讨论】:

我可以确认这种方法在我刚刚使用时有效。这种方法实际上比公认的答案更好,因为它不需要脚本任务,完全可以在 SSIS 中完成。

以上是关于防止平面文件目标中的重复标题 - SSIS的主要内容,如果未能解决你的问题,请参考以下文章

SSIS 2008 - 在平面文件目标中导出为指数值的浮点值

平面文件到 SSIS 中的 Netezza 加载

如何使用 SSIS 从平面文件中删除重复的行?

SSIS“数据流任务”平面文件目标中没有记录

SSIS:使用变量作为平面文件目标的名称

在 SSIS 中将 ODBC DB2 源转换为平面文件错误