SSIS - 脚本组件,将单行拆分为多行(父子变体)

Ele*_*low 5 sql vb.net ssis etl

在此先感谢您的帮助.我需要帮助编写SSIS脚本组件来将单行划分为多行.有很多有用的博客和帖子我在下面看了一下:

http://beyondrelational.com/ask/public/questions/1324/ssis-script-component-split-single-row-to-multiple-rows-parent-child-variation.aspx

http://bi-polar23.blogspot.com/2008/06/splitting-delimited-column-in-ssis.html

但是,我需要一些额外的帮助来完成项目的编码.基本上这就是我想要做的.

输入数据


    ID               Item Name
    1                Apple01,02,Banana01,02,03
    2                Spoon1,2,Fork1,2,3,4

输出数据


    ParentID      ChildID          Item Name
    1             1                Apple01
    1             2                Apple02
    1             3                Banana01
    1             4                Banana02
    1             5                Banana03
    2             1                Spoon1
    2             2                Spoon2
    2             3                Fork1
    2             4                Fork2
    2             5                Fork3
    2             6                Fork4

下面是我尝试编码,但如果它不合逻辑,请随意修改整体.SSIS异步输出已设置.

Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
    Dim posID As Integer, childID As Integer
    Dim delimiter As String = ","
    Dim txtHolder As String, suffixHolder As String
    Dim itemName As String = Row.ItemName
    Dim keyField As Integer = Row.ID

    If Not (String.IsNullOrEmpty(itemList)) Then

        Dim inputListArray() As String = _
        itemList.Split(New String() {delimiter}, _
        StringSplitOptions.RemoveEmptyEntries)

        For Each item As String In inputListArray
            Output0Buffer.AddRow()
            Output0Buffer.ParentID = keyField

            If item.Length >= 3 Then
                txtHolder = Trim(item)
                Output0Buffer.ItemName = txtHolder

                'when item length is less than 3, it's suffix
            Else
                suffixHolder = Trim(item)
                txtHolder = Left(txtHolder.ToString(), Len(txtHolder) _
                    - Len(suffixHolder)) & suffixHolder.ToString()
                Output0Buffer.ItemName = txtHolder
            End If
        Next
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

当前代码生成以下输出

ID           Item Name
1            Apple01
1            02
1            Banana01
1            02
1            03
2            Spoon1
2            2
2            Fork1
2            2
2            3
2            4

bil*_*nkc 8

如果我在这个回答中表现得很迂腐,那不是我的意图.根据评论"我是新编码和故障排除问题",我想了解我的观察以及我是如何找到它们的.

问题分析

期望的是基于与该行相关联的定界字段将单个行分成多个输出行.

现在的代码是生成适当的行数,因此您可以使脚本的异步部分(拆分)工作,这是一个加号.需要做的是我们需要1)填充子ID列2)在生成子项时将项前缀应用于所有后续行.

我对待这样的大多数问题.我想要完成什么?什么工作?什么不起作用?需要做些什么才能使其发挥作用.将问题分解为越来越小的问题最终将导致您可以做的事情.

代码观察

在提供的代码中粘贴会导致未声明itemList的错误.根据用法,它似乎是itemName.

修复之后,您应该注意到IDE指示您有2个未使用的变量(posID,childID),并且variable txHolder is used before it's been assigned a value. A null reference exception could result at runtime.我的同事经常评论警告是尚未成长的错误所以我作为一个初出茅庐的开发人员的建议是要注意警告,除非您明确指望编译器警告您所述方案.

入门

在解决Child ID情况与名称前缀/后缀之间的选择之间做出选择,我从一个简单的开始,即孩子id

生成代理键

这是一个奇特的标题短语,如果你搜索你有很多命中ssistalk或sqlis或任何一些非常聪明的博客.魔鬼当然知道要搜索什么.没有你在哪里计算或将子id值分配给流,这当然是它没有出现在那里的原因.

我们只需要生成一个单调递增的数字,每次源ID改变时都会重置.我假设入站数据在传入数据中是唯一的,例如销售发票号码是唯一的,我们将拆分购买的物品.但是,如果在数据集中重复这些ID,则可能不是代表发票号,而是代表销售员ID.销售人员1可以在销售蔬菜的批次中有另一行.这是一个更复杂的场景,如果更好地描述您的源数据,我们可以重新审视.

生成我们的代理键有两个部分(同样,将问题分解成更小的部分).要做的第一件事就是制作一个从1到N的数字.你已经定义了一个childId变量来为此服务.初始化此变量(1),然后在foreach循环内增加它.

现在我们计算,我们需要将该值推送到输出流.将这两个步骤放在一起看起来就像

        childID = 1
        For Each item As String In inputListArray
            Output0Buffer.AddRow()
            Output0Buffer.ParentId = keyField
            Output0Buffer.ChildId = childID
            ' There might be VB shorthand for ++
            childID = childID + 1
Run Code Online (Sandbox Code Playgroud)

运行包并成功!从列表中抓取生成代理键. 代理密钥生成

字符串糖化

我不知道在问题的另一半需要做什么的一个奇特的术语,但我需要一些标题.鉴于源数据,这个可能更难以正确.您已经提供了Apple01,Banana01,Spoon1,Fork1的价值.看起来那里有一个模式(名称与代码连接)但是它是什么?你的代码表明,如果它小于3,它是一个后缀,但你怎么知道基数是什么?第一行使用前导0并且长度为两位数,而第二行不使用前导零.这是您需要了解数据的地方.识别第一行"代码"部分的规则是什么?一些可能的算法

  • 强制您的上游数据提供商提供一致的长度代码(我认为这在我的13年中曾经工作过一次,但是从来没有因为反击来源而受到伤害)
  • 假设代码始终为数字,则按逆序测试每个字符,测试是否可以转换为整数(处理可变长度代码)
  • 假设split数组中的第二个元素将提供代码的长度.这是您使用代码的方法,它实际上是有效的.

除了修复局部变量ItemName/itemList之外,我没有做任何更改以使生成的项名称有效.最终代码通过删除PosID并将txtHolder初始化为空字符串来消除警告.

Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
    Dim childID As Integer
    Dim delimiter As String = ","
    Dim txtHolder As String = String.Empty, suffixHolder As String
    Dim itemName As String = Row.ItemName
    Dim keyField As Integer = Row.ID

    If Not (String.IsNullOrEmpty(itemName)) Then

        Dim inputListArray() As String = _
        itemName.Split(New String() {delimiter}, _
        StringSplitOptions.RemoveEmptyEntries)

        ' The inputListArray (our split out field)
        ' needs to generate values from 1 to N
        childID = 1
        For Each item As String In inputListArray
            Output0Buffer.AddRow()
            Output0Buffer.ParentId = keyField
            Output0Buffer.ChildId = childID
            ' There might be VB shorthand for ++
            childID = childID + 1

            If item.Length >= 3 Then
                txtHolder = Trim(item)
                Output0Buffer.ItemName = txtHolder
            Else
                'when item length is less than 3, it's suffix
                suffixHolder = Trim(item)
                txtHolder = Left(txtHolder.ToString(), Len(txtHolder) _
                    - Len(suffixHolder)) & suffixHolder.ToString()
                Output0Buffer.ItemName = txtHolder
            End If
        Next
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)