SSIS - компонент сценария, разделение одной строки на несколько строк (родительское дочернее изменение) - PullRequest
5 голосов
/ 06 марта 2012

Заранее спасибо за помощь.Мне нужна помощь в написании компонента сценария 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 / split-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

Текущий код создает следующий вывод

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

1 Ответ

8 голосов
/ 06 марта 2012

Если я столкнусь с педантизмом в этом ответе, это не мое намерение.Исходя из комментария «Я новичок в кодировании и имею проблемы с устранением неполадок», я хотел просмотреть мои наблюдения и то, как я к ним пришел.

Анализ проблем

Желание разбитьодна строка в несколько выходных строк на основе поля с разделителями, связанного со строкой.

Код в его нынешнем виде генерирует соответствующее количество строк, поэтому асинхронная часть (разбиение) сценария работает.так что это плюс.Что должно произойти, так это то, что нам нужно: 1) заполнить столбец Child 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 и именемматериал префикса / суффикса, я бы начал с простого, дочернего идентификатора

Генерация суррогатного ключа

Это необычная заглавная фраза, которая, если вы будете искать, у вас будет много хитовчтобы ssistalk или sqlis или любой из ряда сказочно умных блоггеров.Дьявол, конечно, знает, что искать.Нет, где вы когда-либо вычисляете или присваиваете значение дочернего идентификатора потоку, поэтому, конечно, именно поэтому оно там не отображается.

Нам просто нужно сгенерировать монотонно увеличивающееся число, которое сбрасывается каждый раз, когда идентификатор источникаизменения.Я предполагаю, что входящий идентификатор является уникальным во входящих данных, например, номер счета на продажу будет уникальным, и мы разделяем приобретенные товары.Однако, если эти идентификаторы были повторены в наборе данных, возможно, вместо того, чтобы представлять номера счета, они являются идентификатором продавца.У продавца 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

Запустите пакет и добейтесь успеха!Вычеркните сгенерированный суррогатный ключ из списка.surrogate key generated

Струнное затирание

Я не знаю причудливого термина для того, что нужно сделать в другой половине проблемы, но мне нужен был заголовок для этого раздела.Учитывая исходные данные, это может быть сложнее понять правильно.Вы указали стоимость Apple01, Banana01, Spoon1, Fork1.Похоже, что там есть шаблон (имя, соединенное с кодом), но что это?Ваш код указывает, что если он меньше 3, это суффикс, но как узнать, что такое base ?Первая строка использует начальный 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
...