Поделиться через


Синтаксический анализ текстовых файлов нестандартного формата в компоненте сценария

Если исходные данные организованы в нестандартном формате, может оказаться удобнее объединить всю логику синтаксического анализа в единый скрипт вместо создания цепочки преобразований служб Integration Services, приводящих к тому же результату.

Пример 1. Синтаксический анализ записей, разделенных на строки

Пример 2. Разделение родительских и дочерних записей

ПримечаниеПримечание

Если нужно создать компонент, который будет удобно использовать в нескольких задачах потока данных и нескольких пакетах, рекомендуется начать разработку пользовательского компонента потока данных с этого образца компонента сценария. Дополнительные сведения см. в разделе Разработка пользовательского компонента потока данных.

Пример 1. Синтаксический анализ записей, разделенных на строки

В этом примере берется текстовый файл, в котором каждый столбец данных размещается на новой строке, и с помощью синтаксического анализа, реализованного в компоненте сценария, преобразуется в целевую таблицу.

Дополнительные сведения о настройке компонента сценария для использования в качестве преобразования в потоке данных см. в разделах Создание синхронного преобразования с помощью компонента скрипта и Создание асинхронного преобразования с помощью компонента скрипта.

Настройка этого образца компонента скрипта

  1. Создайте и сохраните под именем rowdelimiteddata.txt текстовый файл, содержащий следующие исходные данные:

    FirstName: Nancy
    LastName: Davolio
    Title: Sales Representative
    City: Seattle
    StateProvince: WA
    
    FirstName: Andrew
    LastName: Fuller
    Title: Vice President, Sales
    City: Tacoma
    StateProvince: WA
    
    FirstName: Steven
    LastName: Buchanan
    Title: Sales Manager
    City: London
    StateProvince:
    
  2. Откройте среду Management Studio и установите соединение с экземпляром SQL Server.

  3. Выберите целевую базу данных и откройте окно нового запроса. Чтобы создать целевую таблицу, выполните в окне запросов следующий скрипт.

    create table RowDelimitedData
    (
    FirstName varchar(32),
    LastName varchar(32),
    Title varchar(32),
    City varchar(32),
    StateProvince varchar(32)
    )
    
  4. В среде BI Development Studio создайте новый пакет служб Integration Services с именем ParseRowDelim.dtsx.

  5. Добавьте в пакет диспетчер соединений с неструктурированными файлами, назовите этот диспетчер «RowDelimitedData» и настройте на соединение с файлом rowdelimiteddata.txt, созданным на предыдущем шаге.

  6. Добавьте в пакет диспетчер соединений OLE DB и настройте его на соединение с экземпляром SQL Server и базой данных, в которой создана целевая таблица.

  7. Добавьте в пакет задачу потока данных и щелкните вкладку Поток данных конструктора служб SSIS.

  8. Добавьте к потоку данных источник «Неструктурированный файл» и настройте его на использование диспетчера соединений RowDelimitedData. На странице Столбцы в редакторе источника «Неструктурированный файл» выберите единственный доступный внешний столбец.

  9. Добавьте в поток данных компонент сценария и настройте его в качестве преобразования. Соедините выход источника «Неструктурированный файл» с компонентом сценария.

  10. Дважды щелкните компонент сценария, чтобы открыть редактор преобразования «Сценарий».

  11. На странице Входные столбцы в редакторе преобразования «Сценарий» выберите единственный доступный входной столбец.

  12. На странице Входы и выводыредактора преобразования «Скрипт» выберите вывод 0 и установите его SynchronousInputID в значение «Нет». Создайте 5 выходных столбцов со строковым типом [DT_STR] и длиной 32:

    • FirstName

    • LastName

    • Title

    • City

    • StateProvince

  13. На странице Сценарийредактора преобразования «Сценарий» нажмите кнопку Изменить сценарий и введите код, содержащийся в классе ScriptMain примера. Закройте среду разработки сценариев и редактор преобразования «Сценарий».

  14. Добавьте в поток данных назначение «SQL Server». Настройте его на использование диспетчера соединений OLE DB и таблицы RowDelimitedData. Настройте выход компонента сценария на это назначение.

  15. Запустите пакет. По завершении работы пакета исследуйте записи в целевой таблице SQL Server.

    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)

        Dim columnName As String
        Dim columnValue As String

        ' Check for an empty row.
        If Row.Column0.Trim.Length > 0 Then
            columnName = Row.Column0.Substring(0, Row.Column0.IndexOf(":"))
            ' Check for an empty value after the colon.
            If Row.Column0.Substring(Row.Column0.IndexOf(":")).TrimEnd.Length > 1 Then
                ' Extract the column value from after the colon and space.
                columnValue = Row.Column0.Substring(Row.Column0.IndexOf(":") + 2)
                Select Case columnName
                    Case "FirstName"
                        ' The FirstName value indicates a new record.
                        Me.Output0Buffer.AddRow()
                        Me.Output0Buffer.FirstName = columnValue
                    Case "LastName"
                        Me.Output0Buffer.LastName = columnValue
                    Case "Title"
                        Me.Output0Buffer.Title = columnValue
                    Case "City"
                        Me.Output0Buffer.City = columnValue
                    Case "StateProvince"
                        Me.Output0Buffer.StateProvince = columnValue
                End Select
            End If
        End If

    End Sub
public override void Input0_ProcessInputRow(Input0Buffer Row)
    {

        string columnName;
        string columnValue;

        // Check for an empty row.
        if (Row.Column0.Trim().Length > 0)
        {
            columnName = Row.Column0.Substring(0, Row.Column0.IndexOf(":"));
            // Check for an empty value after the colon.
            if (Row.Column0.Substring(Row.Column0.IndexOf(":")).TrimEnd().Length > 1)
            // Extract the column value from after the colon and space.
            {
                columnValue = Row.Column0.Substring(Row.Column0.IndexOf(":") + 2);
                switch (columnName)
                {
                    case "FirstName":
                        // The FirstName value indicates a new record.
                        this.Output0Buffer.AddRow();
                        this.Output0Buffer.FirstName = columnValue;
                        break;
                    case "LastName":
                        this.Output0Buffer.LastName = columnValue;
                        break;
                    case "Title":
                        this.Output0Buffer.Title = columnValue;
                        break;
                    case "City":
                        this.Output0Buffer.City = columnValue;
                        break;
                    case "StateProvince":
                        this.Output0Buffer.StateProvince = columnValue;
                        break;
                }
            }
        }

    }

Пример 2. Разделение родительских и дочерних записей

В этом примере берется текстовый файл, в котором за строкой-разделителем следует родительская строка, а за ней — неопределенное количество дочерних строк, и с помощью синтаксического анализа, реализованного в компоненте сценария, преобразуется в две правильным образом нормализованные целевые таблицы — родительскую и дочернюю. Этот простой пример легко адаптировать для исходных файлов, использующих несколько строк или столбцов для каждой родительской и дочерней записи: главное, чтобы начало и конец каждой записи были как-то обозначены.

ПредупреждениеВнимание!

Данный образец предназначен только для демонстрационных целей. Если запустить образец несколько раз, он вставит в целевую таблицу повторяющиеся ключевые значения.

Дополнительные сведения о настройке компонента сценария для использования в качестве преобразования в потоке данных см. в разделах Создание синхронного преобразования с помощью компонента скрипта и Создание асинхронного преобразования с помощью компонента скрипта.

Настройка этого образца компонента скрипта

  1. Создайте и сохраните под именем parentchilddata.txt текстовый файл, содержащий следующие исходные данные:

******** PARENT 1 DATA child 1 data child 2 data child 3 data child 4 data ******** PARENT 2 DATA child 5 data child 6 data child 7 data child 8 data ********

  1. Откройте среду Среда SQL Server Management Studio и установите соединение с экземпляром SQL Server.

  2. Выберите целевую базу данных и откройте окно нового запроса. Чтобы создать целевые таблицы, выполните в окне запросов следующий сценарий.

    CREATE TABLE [dbo].[Parents](
    [ParentID] [int] NOT NULL,
    [ParentRecord] [varchar](32) NOT NULL,
     CONSTRAINT [PK_Parents] PRIMARY KEY CLUSTERED 
    ([ParentID] ASC)
    )
    GO
    CREATE TABLE [dbo].[Children](
    [ChildID] [int] NOT NULL,
    [ParentID] [int] NOT NULL,
    [ChildRecord] [varchar](32) NOT NULL,
     CONSTRAINT [PK_Children] PRIMARY KEY CLUSTERED 
    ([ChildID] ASC)
    )
    GO
    ALTER TABLE [dbo].[Children] ADD CONSTRAINT [FK_Children_Parents] FOREIGN KEY([ParentID])
    REFERENCES [dbo].[Parents] ([ParentID])
    
  3. В среде Business Intelligence Development Studio создайте новый пакет служб Integration Services с именем «SplitParentChild.dtsx».

  4. Добавьте в пакет диспетчер соединений с неструктурированными файлами, назовите этот диспетчер «ParentChildData» и настройте на соединение с файлом parentchilddata.txt, созданным на предыдущем шаге.

  5. Добавьте в пакет диспетчер соединений OLE DB и настройте его на соединение с экземпляром SQL Server и базой данных, в которой созданы целевые таблицы.

  6. Добавьте в пакет задачу потока данных и щелкните вкладку Поток данных конструктора служб SSIS.

  7. Добавьте к потоку данных источник «Неструктурированный файл» и настройте его на использование диспетчера соединений ParentChildData. На странице Столбцы в редакторе источника «Неструктурированный файл» выберите единственный доступный внешний столбец.

  8. Добавьте в поток данных компонент сценария и настройте его в качестве преобразования. Соедините выход источника «Неструктурированный файл» с компонентом сценария.

  9. Дважды щелкните компонент сценария, чтобы открыть редактор преобразования «Сценарий».

  10. На странице Входные столбцы в редакторе преобразования «Сценарий» выберите единственный доступный входной столбец.

  11. На странице Входы и выводыредактора преобразования «Сценарий», установите выводу значение 0, переименуйте его в ParentRecords и задайте для параметра SynchronousInputID значение «Нет». Создайте 2 выходных столбца.

    • ParentID (первичный ключ), имеющий тип четырехбайтового целого числа со знаком [DT_I4].

    • ParentRecord, строкового типа [DT_STR], длиной 32 символа.

  12. Создайте второй вывод и установите для него имя ChildRecords. Параметр SynchronousInputID для нового вывода уже установлен в значение «Нет». Создайте 3 выходных столбца.

    • ChildID (первичный ключ), имеющий тип четырехбайтового целого числа со знаком [DT_I4].

    • ParentID (внешний ключ), также типа «четырехбайтовое целое число со знаком» [DT_I4].

    • ChildRecord, строкового типа [DT_STR], длиной 50 символов.

  13. На странице Сценарийредактора преобразования «Сценарий» нажмите кнопку Изменить сценарий. Вставьте код, приведенный в примере, в класс ScriptMain. Закройте среду разработки сценариев и редактор преобразования «Сценарий».

  14. Добавьте в поток данных назначение «SQL Server». Подключите выход ParentRecords компонента сценария к этому назначению. Настройте его на использование диспетчера соединений OLE DB и таблицы Parents.

  15. Добавьте к потоку данных еще одно назначение «SQL Server». Настройте выход ChildRecords компонента сценария на это назначение. Настройте его на использование диспетчера соединений OLE DB и таблицы Children.

  16. Запустите пакет. По завершении работы пакета исследуйте записи в двух целевых таблицах SQL Server.

    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)

        Static nextRowIsParent As Boolean = False
        Static parentCounter As Integer = 0
        Static childCounter As Integer = 0

        ' If current row starts with separator characters,
        '  then following row contains new parent record.
        If Row.Column0.StartsWith("***") Then
            nextRowIsParent = True
        Else
            If nextRowIsParent Then
                ' Current row contains parent record.
                parentCounter += 1
                Me.ParentRecordsBuffer.AddRow()
                Me.ParentRecordsBuffer.ParentID = parentCounter
                Me.ParentRecordsBuffer.ParentRecord = Row.Column0
                nextRowIsParent = False
            Else
                ' Current row contains child record.
                childCounter += 1
                Me.ChildRecordsBuffer.AddRow()
                Me.ChildRecordsBuffer.ChildID = childCounter
                Me.ChildRecordsBuffer.ParentID = parentCounter
                Me.ChildRecordsBuffer.ChildRecord = Row.Column0
            End If
        End If

    End Sub
public override void Input0_ProcessInputRow(Input0Buffer Row)
    {

    int static_Input0_ProcessInputRow_childCounter = 0;
    int static_Input0_ProcessInputRow_parentCounter = 0;
    bool static_Input0_ProcessInputRow_nextRowIsParent = false;

        // If current row starts with separator characters, 
        // then following row contains new parent record. 
        if (Row.Column0.StartsWith("***"))
        {
            static_Input0_ProcessInputRow_nextRowIsParent = true;
        }
        else
        {
            if (static_Input0_ProcessInputRow_nextRowIsParent)
            {
                // Current row contains parent record. 
                static_Input0_ProcessInputRow_parentCounter += 1;
                this.ParentRecordsBuffer.AddRow();
                this.ParentRecordsBuffer.ParentID = static_Input0_ProcessInputRow_parentCounter;
                this.ParentRecordsBuffer.ParentRecord = Row.Column0;
                static_Input0_ProcessInputRow_nextRowIsParent = false;
            }
            else
            {
                // Current row contains child record. 
                static_Input0_ProcessInputRow_childCounter += 1;
                this.ChildRecordsBuffer.AddRow();
                this.ChildRecordsBuffer.ChildID = static_Input0_ProcessInputRow_childCounter;
                this.ChildRecordsBuffer.ParentID = static_Input0_ProcessInputRow_parentCounter;
                this.ChildRecordsBuffer.ChildRecord = Row.Column0;
            }
        }

    }
Значок служб Integration Services (маленький) Будьте в курсе новых возможностей cлужб Integration Services

Чтобы загружать новейшую документацию, статьи, образцы и видеоматериалы от корпорации Майкрософт, а также лучшие решения от участников сообщества, посетите страницу служб Integration Services на сайтах MSDN или TechNet:

Чтобы получать автоматические уведомления об этих обновлениях, подпишитесь на RSS-каналы, предлагаемые на этой странице.