Analizar formatos de archivo de texto no estándar con el componente de script
Cuando los datos de origen están organizados en un formato no estándar, puede resultar más conveniente consolidar toda la lógica de análisis en un único script que encadenar varias transformaciones de Integration Services para lograr el mismo resultado.
Ejemplo 1: analizar registros delimitados por fila
Ejemplo 2: dividir registros primarios y secundarios
[!NOTA]
Si desea crear un componente que pueda reutilizar más fácilmente en varias tareas de flujo de datos y varios paquetes, puede utilizar el código de este ejemplo de componente de script como punto de inicio para el componente de flujo de datos personalizado. Para obtener más información, vea Desarrollar un componente de flujo de datos personalizado.
Ejemplo 1: analizar registros delimitados por fila
En este ejemplo se muestra cómo tomar un archivo de texto en el que cada columna de datos aparece en una línea independiente y analizarlo en una tabla de destino utilizando el componente de script.
Para obtener más información sobre cómo configurar el componente de script para su uso como una transformación en el flujo de datos, vea Crear una transformación sincrónica con el componente de script y Crear una transformación asincrónica con el componente de script.
Para configurar este ejemplo de componente de script
Cree y guarde un archivo de texto denominado rowdelimiteddata.txt que contenga los datos de origen siguientes:
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 Management Studio y conéctese a una instancia de SQL Server.
Seleccione una base de datos de destino y abra una nueva ventana de consulta. En la ventana de consulta, ejecute el siguiente script para crear la tabla de destino:
create table RowDelimitedData ( FirstName varchar(32), LastName varchar(32), Title varchar(32), City varchar(32), StateProvince varchar(32) )
Abra BI Development Studio y cree un nuevo paquete de Integration Services denominado ParseRowDelim.dtsx.
Agregue un administrador de conexión de archivos planos al paquete, denomínelo RowDelimitedData y configúrelo para conectarse al archivo rowdelimiteddata.txt que creó en un paso anterior.
Agregue un administrador de conexión OLE DB al paquete y configúrelo para conectarse a la instancia de SQL Server y a la base de datos donde creó la tabla de destino.
Agregue una tarea de flujo de datos al paquete y haga clic en la ficha Flujo de datos del Diseñador SSIS.
Agregue un origen de archivo plano al flujo de datos y configúrelo para utilizar el administrador de conexión RowDelimitedData. En la página Columnas del Editor de origen de archivos planos, seleccione la única columna externa disponible.
Agregue un componente de script al flujo de datos y configúrelo como una transformación. Conecte la salida del origen de archivo plano al componente de script.
Haga doble clic en el componente de script para mostrar el Editor de transformación Script.
En la página Columnas de entrada del Editor de transformación Script, seleccione la única columna de entrada disponible.
En la página Entradas y salidas del Editor de transformación Script, seleccione Salida 0 y establezca SynchronousInputID en 0. Cree 5 columnas de salida, todas del tipo cadena [DT_STR] con una longitud de 32:
FirstName
LastName
Title
City
StateProvince
En la página Script del Editor de transformación Script, haga clic en Editar script y escriba el código que se muestra en la clase ScriptMain del ejemplo. Cierre el entorno de desarrollo de scripts y el Editor de transformación Script.
Agregue un destino de SQL Server al flujo de datos. Configúrelo para utilizar el administrador de conexión OLE DB y la tabla RowDelimitedData. Conecte la salida del componente de script a este destino.
Ejecute el paquete. Después de que el paquete haya finalizado, examine los registros en la tabla de destino de 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;
}
}
}
}
Ejemplo 2: dividir registros primarios y secundarios
Este ejemplo muestra cómo tomar un archivo de texto, en el que una fila de separación precede a una fila de registro primario a la que siguen un número indefinido de filas de registro secundario, y cómo analizarlo en tablas de destino primarias y secundarias correctamente normalizadas mediante el componente de script. Este sencillo ejemplo se puede adaptar fácilmente a archivos de origen que utilizan más de una fila o columna para cada registro primario y secundario, siempre que exista una forma de identificar el principio y el final de cada registro.
Advertencia |
---|
El único fin de este ejemplo es usarlo para realizar una demostración. Si ejecuta más de una vez el ejemplo, se insertan valores de clave duplicados en la tabla de destino. |
Para obtener más información sobre cómo configurar el componente de script para su uso como una transformación en el flujo de datos, vea Crear una transformación sincrónica con el componente de script y Crear una transformación asincrónica con el componente de script.
Para configurar este ejemplo de componente de script
- Cree y guarde un archivo de texto denominado parentchilddata.txt que contenga los datos de origen siguientes:
******** 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 SQL Server Management Studio y conéctese a una instancia de SQL Server.
Seleccione una base de datos de destino y abra una nueva ventana de consulta. En la ventana de consulta, ejecute el siguiente script para crear las tablas 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 Business Intelligence Development Studio y cree un nuevo paquete de Integration Services denominado SplitParentChild.dtsx.
Agregue un administrador de conexión de archivos planos al paquete, denomínelo ParentChildData y configúrelo para conectarse al archivo parentchilddata.txt que creó en un paso anterior.
Agregue un administrador de conexión OLE DB al paquete y configúrelo para conectarse a la instancia de SQL Server y a la base de datos donde creó las tablas de destino.
Agregue una tarea de flujo de datos al paquete y haga clic en la ficha Flujo de datos del Diseñador SSIS.
Agregue un origen de archivo plano al flujo de datos y configúrelo para utilizar el administrador de conexión ParentChildData. En la página Columnas del Editor de origen de archivos planos, seleccione la única columna externa disponible.
Agregue un componente de script al flujo de datos y configúrelo como una transformación. Conecte la salida del origen de archivo plano al componente de script.
Haga doble clic en el componente de script para mostrar el Editor de transformación Script.
En la página Columnas de entrada del Editor de transformación Script, seleccione la única columna de entrada disponible.
En la página Entradas y salidas del Editor de transformación Script, seleccione Salida 0, cámbiele el nombre a ParentRecords y establezca SynchronousInputID en Ninguno. Cree 2 columnas de salida:
ParentID (la clave principal), de tipo entero de cuatro bytes con signo [DT_I4]
ParentRecord, de tipo cadena [DT_STR] con una longitud de 32.
Cree una segunda salida y denomínela ChildRecords. El valor SynchronousInputID de la nueva salida ya está establecido en Ninguno. Cree 3 columnas de salida:
ChildID (la clave principal), de tipo entero de cuatro bytes con signo [DT_I4]
ParentID (la clave externa), también de tipo entero de cuatro bytes con signo [DT_I4]
ChildRecord, de tipo cadena [DT_STR] con una longitud de 50.
En la página Script del Editor de transformación Script, haga clic en Editar script. En la clase ScriptMain, escriba el código mostrado en el ejemplo. Cierre el entorno de desarrollo de scripts y el Editor de transformación Script.
Agregue un destino de SQL Server al flujo de datos. Conecte la salida ParentRecords del componente de script a este destino. Configúrela para utilizar el administrador de conexión OLE DB y la tabla Parents.
Agregue otro destino de SQL Server al flujo de datos. Conecte la salida ChildRecords del componente de script a este destino. Configúrela para utilizar el administrador de conexión OLE DB y la tabla Children.
Ejecute el paquete. Después de que el paquete haya finalizado, examine los registros primarios y secundarios en las dos tablas de destino de 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;
}
}
}
|