Compartilhar via


Analisando formatos de arquivo de texto fora do padrão com o componente Script

Aplica-se a: Tempo de execução de integração do SSIS do SQL Server no Azure Data Factory

Quando seus dados de origem estiverem dispostos em um formato não padrão, talvez seja mais conveniente consolidar toda a sua lógica de análise em um único script do que reunir várias transformações Integration Services para chegar ao mesmo resultado.

Exemplo 1: analisar registros delimitados por linha

Exemplo 2: dividir registros pai e filho

Observação

Se desejar criar um componente que possa ser reutilizado mais facilmente em várias tarefas de fluxo de dados e em vários pacotes, procure utilizar o código deste exemplo de componente Script como o ponto inicial de um componente de fluxo de dados personalizado. Para obter mais informações, consulte Desenvolvendo um componente de fluxo de dados personalizado.

Exemplo 1: Analisando registros delimitados por linha

Este exemplo mostra como utilizar um arquivo de texto em que cada coluna de dados aparece em uma linha separada e analisá-lo em uma tabela de destino usando o componente Script.

Para obter mais informações sobre como configurar o componente Script para uso como uma transformação no fluxo de dados, consulte Criando uma transformação síncrona com o componente Script e Criando uma transformação assíncrona com o componente Script.

Para configurar esse exemplo de componente Script

  1. Crie e salve um arquivo de texto nomeado rowdelimiteddata.txt contendo os seguintes dados de origem:

    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. Abra o Management Studio e conecte-se a uma instância do SQL Server.

  3. Selecione um banco de dados de destino e abra uma nova janela de consulta. Na janela de consulta, execute o seguinte script para criar a tabela de destino:

    create table RowDelimitedData  
    (  
    FirstName varchar(32),  
    LastName varchar(32),  
    Title varchar(32),  
    City varchar(32),  
    StateProvince varchar(32)  
    )  
    
    
  4. Abra o SQL Server Data Tools e crie um novo pacote de Integration Services nomeado ParseRowDelim.dtsx.

  5. Adicione um gerenciador de conexões de arquivos simples ao pacote, nomeie-o como RowDelimitedData e configure-o para conectá-lo ao arquivo rowdelimiteddata.txt criado em uma etapa anterior.

  6. Adicione um gerenciador de conexões OLE DB ao pacote e configure-o para conectá-lo à instância do SQL Server e ao banco de dados em que você criou a tabela de destino.

  7. Adicione uma tarefa de Fluxo de Dados ao pacote e clique na guia Fluxo de Dados do Designer SSIS.

  8. Adicione uma Fonte de Arquivo Simples ao fluxo de dados e configure-a para usar o gerenciador de conexões do RowDelimitedData. Na página Colunas do Editor de Fonte de Arquivo Simples, selecione a única coluna externa disponível.

  9. Adicione um Componente Script ao fluxo de dados e configure-o como uma transformação. Conecte a saída da Fonte de Arquivo Simples ao Componente Script.

  10. Clique duas vezes no componente Script para exibir o Editor de Transformação Scripts.

  11. Na página Colunas de Entrada do Editor de Transformação Scripts, selecione a única coluna de entrada disponível.

  12. Na página Entradas e Saídas do Editor de Transformação Scripts, selecione Saída 0 e defina seu SynchronousInputID como Nenhum. Crie 5 colunas de saída, todas com tipo cadeia de caracteres [DT_STR] com comprimento 32:

    • Nome

    • LastName

    • Title

    • City

    • StateProvince

  13. Na página Script do Editor de Transformação Scripts, clique em Editar Script e digite o código mostrado na classe ScriptMain do exemplo. Feche o ambiente de desenvolvimento de scripts e o Editor de Transformação Scripts.

  14. Adicione um Destino de SQL Server ao fluxo de dados. Configure-o para usar o gerenciador de conexões do OLE DB e a tabela RowDelimitedData. Conecte a saída do Componente Script a este destino.

  15. Execute o pacote. Depois da conclusão do pacote, examine os registros na tabela de destino 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;  
                }  
            }  
        }  
  
    }  

Exemplo 2: Dividindo registros pai e filho

Este exemplo mostra como utilizar um arquivo de texto, em que uma linha delimitadora precede uma linha de registro pai, que é seguida de um número indefinido de linhas de registro filho, e analisa-as em tabelas de destino pai e filho, adequadamente normalizadas, através do componente Script. Esse exemplo simples pode ser facilmente adaptado para arquivos de origem que utilizam mais de uma linha ou coluna para cada registro pai e filho, desde que exista uma forma de identificar o início e o fim de cada registro.

Cuidado

Esse exemplo é utilizado apenas para fins de demonstração. Se você executar o exemplo mais de uma vez, ele inserirá valores de chave duplicados na tabela de destino.

Para obter mais informações sobre como configurar o componente Script para uso como uma transformação no fluxo de dados, consulte Criando uma transformação síncrona com o componente Script e Criando uma transformação assíncrona com o componente Script.

Para configurar esse exemplo de componente Script

  1. Crie e salve um arquivo de texto nomeado parentchilddata.txt contendo os seguintes dados de origem:

    **********  
    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  
    **********  
    
    
  2. Abra o SQL Server Management Studio e conecte-se a uma instância do SQL Server.

  3. Selecione um banco de dados de destino e abra uma nova janela de consulta. Na janela de consulta, execute o seguinte script para criar as tabelas de destino:

    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])  
    
    
  4. Abra o SQL Server Data Tools (SSDT) e crie um novo pacote Integration Services nomeado SplitParentChild.dtsx.

  5. Adicione um gerenciador de conexões de arquivos simples ao pacote, nomeie-o como ParentChildData e configure-o para conectá-lo ao arquivo parentchilddata.txt criado em uma etapa anterior.

  6. Adicione um gerenciador de conexões OLE DB ao pacote e configure-o para conectar-se à instância do SQL Server e ao banco de dados em que você criou as tabelas de destino.

  7. Adicione uma tarefa de Fluxo de Dados ao pacote e clique na guia Fluxo de Dados do Designer SSIS.

  8. Adicione uma Fonte de Arquivo Simples ao fluxo de dados e configure-a para usar o gerenciador de conexões do ParentChildData. Na página Colunas do Editor de Fonte de Arquivo Simples, selecione a única coluna externa disponível.

  9. Adicione um Componente Script ao fluxo de dados e configure-o como uma transformação. Conecte a saída da Fonte de Arquivo Simples ao Componente Script.

  10. Clique duas vezes no componente Script para exibir o Editor de Transformação Scripts.

  11. Na página Colunas de Entrada do Editor de Transformação Scripts, selecione a única coluna de entrada disponível.

  12. Na página Entradas e Saídas do Editor de Transformação Scripts, selecione Saída 0, renomeie-a como ParentRecords e defina seu SynchronousInputID como Nenhum. Crie 2 colunas de saída:

    • ParentID (a chave primária), de tipo inteiro assinado de quatro bytes [DT_I4]

    • ParentRecord, de cadeia de caracteres de tipo [DT_STR] com comprimento de 32.

  13. Crie uma segunda saída e nomeie-a como ChildRecords. O SynchronousInputID da nova saída já está definido como Nenhum. Crie 3 colunas de saída:

    • ChildID (a chave primária), de tipo inteiro assinado de quatro bytes [DT_I4]

    • ParentID (a chave estrangeira), também de tipo inteiro assinado de quatro bytes [DT_I4]

    • ChildRecord, de cadeia de caracteres de tipo [DT_STR] com comprimento de 50

  14. Na página Script do Editor de Transformação Scripts, clique em Editar Script. Na classe ScriptMain, digite o código mostrado no exemplo. Feche o ambiente de desenvolvimento de scripts e o Editor de Transformação Scripts.

  15. Adicione um Destino de SQL Server ao fluxo de dados. Conecte a saída de ParentRecords do Componente Script a esse destino. Configure-o para usar o gerenciador de conexões OLE DB e a tabela Pais.

  16. Adicione outro Destino de SQL Server ao fluxo de dados. Conecte a saída ChildRecords do Componente Script a esse destino. Configure-o para usar o gerenciador de conexões OLE DB e a tabela Filhos.

  17. Execute o pacote. Depois da conclusão do pacote, examine os registros pai e filho nas duas tabelas de destino do 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;  
            }  
        }  
  
    }  

Consulte Também

Criando uma transformação síncrona com o componente Script
Criar uma transformação assíncrona com o componente de Script