Analisando formatos de arquivo de texto fora do padrão com o componente Script
Aplica-se a: SQL Server SSIS Integration Runtime 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
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:
Abra o Management Studio e conecte-se a uma instância do SQL Server.
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) )
Abra o SQL Server Data Tools e crie um novo pacote de Integration Services nomeado ParseRowDelim.dtsx.
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.
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.
Adicione uma tarefa de Fluxo de Dados ao pacote e clique na guia Fluxo de Dados do Designer SSIS.
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.
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.
Clique duas vezes no componente Script para exibir o Editor de Transformação Scripts.
Na página Colunas de Entrada do Editor de Transformação Scripts, selecione a única coluna de entrada disponível.
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
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.
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.
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
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 **********
Abra o SQL Server Management Studio e conecte-se a uma instância do SQL Server.
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])
Abra o SQL Server Data Tools (SSDT) e crie um novo pacote Integration Services nomeado SplitParentChild.dtsx.
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.
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.
Adicione uma tarefa de Fluxo de Dados ao pacote e clique na guia Fluxo de Dados do Designer SSIS.
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.
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.
Clique duas vezes no componente Script para exibir o Editor de Transformação Scripts.
Na página Colunas de Entrada do Editor de Transformação Scripts, selecione a única coluna de entrada disponível.
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.
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
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.
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.
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.
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