【问题标题】:How can I loop though columns by name in an SSIS Script component?如何在 SSIS 脚本组件中按名称循环遍历列?
【发布时间】:2017-10-19 18:41:08
【问题描述】:

我正在将一个以管道分隔的平面文件加载到临时表中。在加载过程中,SSIS 脚本组件对一行执行一些操作。它可以根据另一个字段中的值在一个字段中设置标志,为某些列添加前缀,或应用格式。例如,如果缺少日期,则会将该字段分配给默认日期。 (如果 Row.EndDate_isNull 则 Row.EndDate = defaultDate)

当需要对一系列行应用相同的转换时,这些脚本会变得很麻烦。例如,一个病历文件可以用三个字段描述 9 个诊断中的每一个:Diagnosis01_Date、Diagnosis01_Code、Diagnosis01_System....Diagnosis09_Date、Diagnosis09_Code、Diagnosis09_System。

我想使用循环对 9 组 3 个字段中的每一个执行操作,而不是编写相同的操作 9 次。

例如,如果我在 VB 中处理一个集合,我会在 Input0_ProcessInputRow 子项中编写类似这样的内容:

For i = 1 to 9
   row.("Diagnosis0"+ i + "_Date").Value = diagnosisDate
   row.("Diagnosis0"+ i + "_System").value = "ICD10"
next i 

然而,在 SSIS 对象模型中,列作为 Input0Buffer 的属性公开,我找不到使用变量来引用它们的方法。那么,我如何可以在 SSIS 脚本组件中创建一个按名称对列进行操作的循环?

编辑:我发现以下来源,尤其是前两个,在我研究这个问题时很有帮助。似乎应该有一个使用 system.reflection 的解决方案,但我只是不太了解 .NET,无法弄清楚。

http://agilebi.com/jwelch/2007/10/21/address-columns-generically-in-a-script-task/

http://agilebi.com/jwelch/2007/06/02/xml-destination-script-component/

http://microsoft-ssis.blogspot.com/2010/12/do-something-for-all-columns-in-your.html

http://toddmcdermid.blogspot.com/2011/05/iterating-over-columns-in-ssis-script.html

http://bidn.com/blogs/MikeDavis/ssis/1800/ssis-for-each-column-in-a-data-flow

https://social.msdn.microsoft.com/Forums/en-US/edbac1df-f05f-40db-820a-e009fae201a4/using-script-destination-object-to-create-and-write-to-new-text-file?forum=sqlintegrationservices&forum=sqlintegrationservices

https://social.msdn.microsoft.com/Forums/en-US/757d11c8-8ad4-4021-a959-1d13c8dfdaa7/how-to-run-a-loop-for-all-columns-in-script-component-input-column-collection-for-each-row?forum=sqlintegrationservices

How can I get the column Value in Script Component in SSIS?

【问题讨论】:

    标签: sql-server ssis etl ssis-2012 system.reflection


    【解决方案1】:

    简单的解决方法

    您可以使用循环将列名存储在 List(of string) 中,并使用 Row.GetType().GetProperties() 动态操作列。

    示例:

    注意:您必须导入 System.ReflectionSystem.LinqSystem.Collections.Generic

    Dim lstDateColumns as new List(of string)
    Dim lstSystemColumns as new List(of string)
    
    For i = 1 to 9
        lstDateColumns.Add("Diagnosis0" & i.toString() & "_Date")
        lstSystemColumns.Add("Diagnosis0" & i.toString() & "_System")
    Next
    
    
    For each  dataColumn as PropertyInfo in Row.GetType().GetProperties()
    
    
        If lstDateColumns.Contains(dataColumn.Name) Then
    
                     dataColumn.SetValue(Row, diagnosisDate, Nothing)
    
         ElseIf lstSystemColumns.Contains(dataColumn.Name) Then
    
                    dataColumn.SetValue(Row, "ICD10", Nothing)
    
         End IF
    Next
    

    您可以过滤列表中的列名

        Dim lstDateColumns As New List(Of String)
        Dim lstSystemColumns As New List(Of String)
    
        For i As Integer = 1 To 9
            lstDateColumns.Add("Diagnosis0" & i.ToString() & "_Date")
            lstSystemColumns.Add("Diagnosis0" & i.ToString() & "_System")
        Next
    
        For Each dataColumn As PropertyInfo In Row.GetType().GetProperties().Where(Function(x) lstDateColumns.Contains(x.Name))
    
            dataColumn.SetValue(Row, diagnosisDate, Nothing)
    
        Next
    
    
        For Each dataColumn As PropertyInfo In Row.GetType().GetProperties().Where(Function(x) lstSystemColumns.Contains(x.Name))
    
            dataColumn.SetValue(Row, "ICD10", Nothing)
    
        Next
    

    参考文献

    【讨论】:

    • 我看到这让我走到了那一步——它将允许我遍历我的字段,因为它们在列表中。有没有办法避免遍历源中的所有列?
    • 我是否担心循环遍历所有列的开销不合理?
    • 你是对的。我认为您可以使用 linq 过滤列名。稍等片刻,我会更新
    • @DataWriter 我更新了我的答案,记得导入System.Linq 库以使用Where 函数
    • 我能否将列表声明为私有模块级变量并在事件 Public Overrides Sub PreExecute() 中添加列名,这样我只需为包执行分配一次值,而不是Input0_ProcessInputRow 触发时为每一行执行此操作?
    猜你喜欢
    • 2018-09-02
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 2021-10-11
    • 2021-08-30
    • 1970-01-01
    • 2022-07-16
    • 1970-01-01
    相关资源
    最近更新 更多