当设置为CRLF时,SSIS读取LF作为终结符

时间:2017-05-24 16:58:06

标签: sql-server ssis etl ssis-2012 flat-file

使用SSIS 2012.我的平面文件连接管理器我有一个分隔文件,其中行分隔符设置为CRLF,但是当它处理文件时,我有一个LF的文本列在里面。这导致它将其读作行终止符,导致其失败。有什么想法吗?

5 个答案:

答案 0 :(得分:3)

在回答之前,我不认为该列仅包含LF,因为如果行分隔符为CRLF,则不会将其视为分隔符。所以它可能是CRLF,但我会给出两种情况的解决方案(CRLF或LF)

解决方案

您可以通过以下步骤解决此问题:

  1. 首先在Flat File连接管理器中添加一列(类型为DT_STR且长度为4000),因此您将每行视为一列。
  2. 在数据流任务中,您必须添加用于修复文件结构的脚本组件。并将行拆分为列。
  3. 简单测试

    我会考虑一个包含以下内容的平面文件

    ID;name;DOB;Notes;ClassID{CRLF}
    1;John;2001-01-01;;1{CRLF}
    2;Moh;2002-01-01;Very cool{LF}
    Genius;2{CRLF}
    3;Ali;2000-01-01;Calm;2{CRLF}
    
    1. 首先,我将添加一个平面文件连接管理器,其中包含以下选项:
      • 行分隔符= {CRLF}
      • 标题行分隔符= {CRLF}
    2. enter image description here

      1. 在DataFlow任务中,我将添加Flat File Source,2 x Script ComponentOLEDB Destination

      2. 在第一个脚本组件中,我将Column0标记为输入,我将添加5个输出列ID,Name,DOB,Notes,ClassID,我将输出同步输入设置为None

      3. enter image description here

        1. 在第一个脚本组件中,我将编写一个脚本,将每一行存储在一个内存变量中,并在行完成且另一行存在时将其分配给输出行。

          Dim strLine As String = String.Empty
          
          Dim strDelimiter As String = ";"
          
          Public Sub EmptyMemoryVariables()
          
          
              strLine = String.Empty
          
          
          End Sub
          
          Public Sub AssignMemoryVariablesToOutput()
          
              With Output0Buffer
          
                  .AddRow()
                  .NewRow = strLine
              End With
          
          End Sub
          
          Public Function AreVariablesEmpty() As Boolean
          
              If strLine = "" Then
          
                  Return True
          
              Else
          
                  Return False
          
              End If
          
          
          End Function
          Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
          
              Dim strColumns As String() = Row.Column0.Split(CChar(strDelimiter))
          
              If strColumns.Length = 5 Then
          
                  If Not AreVariablesEmpty() Then
                      AssignMemoryVariablesToOutput()
                      EmptyMemoryVariables()
                  End If
          
                  strLine = Row.Column0
          
                  AssignMemoryVariablesToOutput()
                  EmptyMemoryVariables()
          
          
              Else
          
                  If strLine.Split(CChar(strDelimiter)).Length = 5 Then
          
                      AssignMemoryVariablesToOutput()
                      EmptyMemoryVariables()
          
                  End If
          
          
                  strLine &= Row.Column0
          
          
          
          
          
          
          
              End If
          
        2. 在第二个脚本组件中,我将每行拆分为列

        3. enter image description here

              Dim strDelimiter As String = ";"
              Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
          
                  Dim strColumns As String() = Row.NewRow.Split(CChar(strDelimiter))
          
          
                  Row.ID = strColumns(0)
                  Row.NAME = strColumns(1)
                  Row.DOB = strColumns(2)
                  Row.NOTES = strColumns(3)
                  Row.CLASSID = strColumns(4)
          
          
              End Sub
          

          重要提示:提供的代码不是最佳的,可能需要更多验证,或者可以更简单,更好,但我试图为您提供解决此问题的方法

答案 1 :(得分:2)

我没有SSIS经验,但作为一名ETL开发人员,我多次遇到过这种情况。因此,我的建议可能无法帮助您解决问题,但希望能指出正确的方向

  • 如果问题字段包含文本限定符(单引号或双引号) 通常)和SSIS支持使用它
  • 此外,如果有选项 强制SSIS使用除LF之外的不同记录分隔符(在本例中为CRLF)我会使用它(希望问题字段文本中没有CRLF)
  • 如果问题字段不是最后一个字段,您可以通过将整个记录读取为单个LF分隔字段来计算去限制器的数量 识别并过滤掉问题记录(如果它们很少) 并尝试将它们缝合回来
  • 如果可能,请将文件作为单个文件读取 记录(如果SSIS有选项)并替换所有LF,只要CR为 来自源
  • 的记录分隔符的一致结束

答案 2 :(得分:1)

谢谢你提出的所有建议。原来,供应商已将文件的编码从Ascii更改为unicode。更改包以读取正确的编码就可以了。

答案 3 :(得分:0)

在平面文件连接管理器组件中,您有一个我忘记了名称的属性,在其中您可以设置行分隔符({CR}{LF}{LF}{CR},...等)。

请尝试调整此属性,我认为它可以正常工作。

答案 4 :(得分:0)

我有与此类似的问题。我有一个以LF为终止符的CSV文件。但是,客户端在两个列中也有CRLF,这导致“找不到列分隔符”错误。

我花了几天的时间使用谷歌搜索解决方案和反复试验,但是我成功了。

最后,我需要两个脚本组件。

在第一个脚本组件中,我有一个名为Output0 string的列,其长度为4000。在脚本中(请参见下文),我使用ReadToEnd加载数据,将CRLF替换为空字符串,然后使用LF作为终结器。

using System.IO;
using System.Text;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
    private StreamReader textReader;
    private string collateralFile;

public override void AcquireConnections(object Transaction)
{

    IDTSConnectionManager100 connMgr = this.Connections.Collateral;
    collateralFile = (string)connMgr.AcquireConnection(null);

}

public override void PreExecute()
{
    base.PreExecute();


}

public override void CreateNewOutputRows()
{

    StreamReader textReader = new StreamReader(collateralFile);
    string collatFile = textReader.ReadToEnd();


    collatFile = collatFile.Replace("\r\n", " ");
    
    String[] lines = collatFile.Split(new char[] { '\n' });
    textReader.Close();


        string nextLine;



        for (int i = 0; i < lines.Length; i++)
        {
            if (lines[i] != null)
            {
                nextLine = lines[i];

                if (!String.IsNullOrEmpty(nextLine))
                {
                    Output0Buffer.AddRow();
                    Output0Buffer.Output0 = nextLine;

                }
            }
          }

        }
    }

我尝试将其再次拆分为列,但返回空值,因此在第二个脚本组件中,我创建了列并将数据加载到脚本中。

public override void Input0_ProcessInputRow(Input0Buffer Row)
{

String[] columns = Row.Output0.Split(',');

Row.Description = columns[0];
Row.LegalDescription = columns[1];
Row.Address1ParsedLine1 = columns[2];
Row.Address1ParsedLine2 = columns[4];
Row.Address1ParsedCityname = columns[5];
Row.Address1ParsedStatecode = columns[6];
Row.Address1ParsedPostalcode = columns[7];
}