【问题标题】:How can I load in a pipe (|) delimited text file that has columns that sometimes contain line breaks?如何加载具有有时包含换行符的列的竖线 (|) 分隔文本文件?
【发布时间】:2017-10-16 22:09:09
【问题描述】:

我已经构建了一个 SSIS 包,可以将多个分隔文本文件加载到 SQL 数据库中。其中一个文件中通常包含行空格,这打破了设置平面文件源并映射到 ado.net 目标的标准数据流任务,因为它在到达换行符时认为它在新行上。发送文件的供应商不想在没有任何编辑的情况下发送文件,此时不能执行 XML。有没有什么办法解决这一问题?我正在考虑编写一个小的 vb.net 程序来纠正文件,以便它们可以在 SSIS 包中工作,但不知道如何编写该逻辑。该文件有 5 列,前 2 列是大整数并且总是包含一些长整数 ID,然后是一个小文本列,它只包含一个短词,然后是一个日期,然后是一个导致问题的长 cmets 字段。 cmets 字段有时是空白的(这没关系),问题是有换行符的行。我永远不知道 cmets 中有多少换行符,有些没有,有些可以连续有几个,甚至多个换行符,所以想知道这是否可能。

5787626|6547599|已批准|2017 年 1 月 10 日|申请费用减免申请已获批准 5443221|7742812|活跃|11/5/2013| 3430962|7643957|重新安排|2016 年 5 月 25 日|拒绝修订条款和条件 申请人有 30 天的时间提交延期文件。 34433624|7673715|拒绝|2017 年 1 月 24 日| 34113575|7653748|有效|1/8/2014|已授予新条款。

示例文件格式。

【问题讨论】:

  • 我做过类似的事情。从我的方法中获取指导​​。我创建了一个包含 30 列的临时表(我的管道分隔列固定为 MAX 30)。现在读取管道分离的列并将它们写入 txt 文件。然后再次从文本中读取并将它们放在临时表中。写入后删除txt文件。希望这有意义吗?
  • 我不明白,如果我将文件加载到暂存表中,那么我将得到一个暂存表,其中的列中的数据没有意义。例如,这会让我在应该只包含一个大整数值的列中留下诸如“申请人有 30 天”之类的文本。
  • 您在寻找什么样的输出?我想我误解了你的输出要求。
  • 我希望能够将平面文件分隔的文本加载到 SQL 表中。问题是平面文件中的最后一列没有结束分隔符,它使用 CRLF(行空间)来指示转到下一行,并且通常最后一列在数据中具有行空间。

标签: vb.net ssis csv


【解决方案1】:

只要有你可以编程/预测的逻辑,就有可能。

我会使用脚本组件作为源来执行此操作,这意味着您无需在处理文件之前重写文件。它还提供了很大的灵活性,例如,您可以将值存储在变量中,同时迭代文件中的多行等。

我最近发布了另一个答案,其中详细说明了如何解决这个问题:SSIS import a Flat File to SQL with the first row as header and last row as a total

在准备好写入行之前将值保存在变量中的示例:-

对于这个例子,我正在写三列,ID1、ID2 和评论。该文件如下所示:

1|2|Comment1
Comment2
4|5|Comment3
Comment4
Comment5
6|7|Comment6

脚本组件包含以下方法。

public override void CreateNewOutputRows()
{
    System.IO.StreamReader reader = null;

    try
    {
        bool readFirstLine = false;
        int id1 = 0;
        int id2 = 0;
        string comments = null;

        reader = new System.IO.StreamReader(Variables.FilePath); // this refers to a package variable that contains the file path

        while (!reader.EndOfStream)
        {
            string line = reader.ReadLine();

            if (line.Contains("|"))
            {
                if (readFirstLine)
                {
                    Output0Buffer.AddRow();

                    Output0Buffer.ID1 = id1;
                    Output0Buffer.ID2 = id2;
                    Output0Buffer.Comments = comments;
                }
                else
                {
                    readFirstLine = true;
                }

                string[] fields = line.Split('|');

                id1 = Convert.ToInt32(fields[0]);
                id2 = Convert.ToInt32(fields[1]);
                comments = fields[2];
            }
            else
            {
                comments += " " + line;
            }

            if (reader.EndOfStream)
            {
                Output0Buffer.AddRow();

                Output0Buffer.ID1 = id1;
                Output0Buffer.ID2 = id2;
                Output0Buffer.Comments = comments;
            }
        }
    }
    catch
    {
        if (reader != null)
        {
            reader.Close();
            reader.Dispose();
        }

        throw;
    }
}

结果集是:

ID1    ID2    Comments
===    ===    ========
1      2      Comment1 Comment2
4      5      Comment3 Comment4 Comment5
6      7      Comment6

【讨论】:

  • 我不能使用子字符串,因为字段中数字/字符的长度不是固定长度,甚至不能将 (|) 字符拆分为数组,因为通常是最后一个cmets 字段为空白,读取 cmets 字段下一行的第一行。
  • 你能不能在你的逻辑中做一些事情,如果一行不包含管道,你只需将该字符串添加到前一行的 cmets 字段的末尾?您可以为每个字段使用变量,并且只有在您知道它完成后才创建一行,即您读取包含管道的新行。
  • 是的,这听起来是个好主意,但不确定如何返回并追加到上一行。
  • 我在答案中添加了一个示例,如果有任何不清楚的地方请告诉我。
  • 没问题!请记住将答案标记为正确。谢谢:)
猜你喜欢
  • 2022-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多