SSIS - Uso de Precedence Constraint para direccionar el Flujo de datos

En éste, mi 3er Post sobre Integration Services voy a mostrarles un ejemplo de cómo desviar el flujo de datos que queremos importar según se cumplan ciertas condiciones. El ejemplo que veremos a continuación, si bien es muy simple, nos servirá para ilustrar una forma de razonamiento muy útil para diversas situaciones.
Supongamos que tenemos una empresa en la que los clientes pueden ser Nacionales e Internacionales. El proceso que debemos realizar debe tomar los datos desde 2 ficheros “.txt” los cuales poseen nombres que los diferencian si se tratan de clientes Nacionales o Extranjeros. El formato del nombre de los ficheros para clientes nacionales es ddmmaaaaNac.txt y para los Internacionales es ddmmaaaaInt.txt y estructuralmente la diferencia es que éstos últimos poseen una columna más denominada “Pais” y por éste motivo deben procesarse por separado, de lo contrario se produciría un error.

Los pasos a seguir en la construcción del ejemplo serán:

1. Creación de Ficheros Origen y Tabla de destino de Datos
2. Creación del Proceso SSIS
3. Ejecución del proceso y análisis de resultados

1. Creación de Ficheros Origen y Tabla de destino de Datos
Para comenzar nuestro ejemplo, debemos crear 4 ficheros “.txt” (ver imagen) en los cuales el separador de columnas es el “tab” y el de filas el “Enter” ({CR}{LF})



Una vez creados estos 4 ficheros con sus respectivos nombres, estructuras y contenidos pasemos a la creación de la tabla destino en SQL Server.
El nombre de la tabla será TablaClientes en la BD Examples y su estructura será la siguiente:



2. Creación del Proceso SSIS
Abriremos el SQL Server Business Intelligence Development Studio donde de crearemos un nuevo proyecto de Integration Services, como nombre le pondremos “Condicional”.
Una vez situados en el Control Flow del Package crearemos 2 variables, la primera se llamará varFileName que contendrá el nombre del fichero que se está procesando en un momento determinado y la variable varFilenationality, la cual albergará los valores “Nac” o “Int” según sea la terminación del archivo procesado. Ambas variables serán de tipo String.



Posteriormente agregaremos las conexiones con los ficheros de Origen y la BD de destino de Datos. Tendremos 2 Flat File Connection, una para los Clientes nacionales y otra para los clientes internacionales, y una OLE DB Connection que se conectará a la BD Examples.
Para las Flat Connections deberemos seleccionar el primer fichero “txt” que creamos con anterioridad según se trate de clientes Nacionales o internacionales, es decir, para la conexión “Clientes Nacionales – Origen” debemos seleccionar como File Name 15102007Nac.txt y para “Clientes Internacionales – Origen” debemos seleccionar como File Name 15102007Int.txt



Además, para estas Flat Connections debemos modificar su propiedad Expressions y colocar como connectionString la variable varFileName. Esto permite que a medida que el foreach recorre los ficheros del directorio, los orígenes de datos obtengan sus datos de los ficheros correspondientes.



Luego, sobre la superficie del Control Flow agregaremos un componente Foreach en el cual definiremos el path que contiene los ficheros y el tipo de ficheros a importar, en nuestro caso “*.txt”



En la opción Variable Mappings del Foreach asignaremos la variable varFileName.



A continuación agregaremos dentro del Foreach un Script Task con el cual podremos determinar si el fichero procesado por el foreach se trata de clientes Nacionales o Internacionales. Renombraremos el script task como “Obtener Ambito Cliente” y lo editaremos. En la opción Script, haremos click en el botón Design Script donde agregaremos el siguiente código:

Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Runtime

Public Class ScriptMain

Public Sub Main()

Dim vars As Variables
Dim FileNationality As String
Dim varsNationality As Variables

'asignamos a la variable local "vars" el contenido de la variable varFileName
'que obtiene el nombre del fichero en el Foreach
Dts.VariableDispenser.LockOneForRead("User::varFileName", vars)

'Procesamos la variable varFileName para obtener el ámbito del fichero txt
FileNationality = vars("varFileName").Value.ToString.Substring(vars("varFileName").Value.ToString.Length - 7, 3)

'instanciamos y asignamos a la variable varFileNationality el ámbito obtenido
Dts.VariableDispenser.LockOneForWrite("varFileNationality", varsNationality)
varsNationality("varFileNationality").Value = FileNationality

Dts.TaskResult = Dts.Results.Success
End Sub

End Class


Resumiendo el código, vemos que obtenemos el nombre del fichero que estamos procesando en este momento procesando la variable varFileName, de la cual extraemos el ámbito (Nac o Int) y lo asignamos a la variable varFileNationality. Ésta variable será la que utilizaremos para desviar el flujo de datos hacia un Data Flow u otro más adelante.

El siguiente paso consiste en crear 2 Data Flow, uno llamado “Clientes Nacionales Data Flow Task” y el otro “Clientes Internacionales Data Flow Task”, donde el primero se encargará de importar en la tabla TablaClientes de la BD Examples los datos relativos a los clientes Nacionales y el segundo, los datos de los clientes Internacionales.

Arrastramos sendas flechas desde el Script hasta los Data Flow recientemente creados y el siguiente paso será editar los Precedence Constraint haciendo doble click sobre las mencionadas flechas que unen el Script con los Data Flow.

Editemos el Precedence Constraint que une el Script con el Clientes Nacionales Data Flow Task. Allí debemos cambiar la Evaluation operation a Expression y dentro del campo homónimo escribir:
@[User::varFileNationality] == "Nac"



Damos OK y repetimos la operación para el Precedence Constraint que une el script con el el Clientes Internacionales Data Flow Task, imitamos la configuración anterior pero reemplazando la Expression por la siguiente:
@[User::varFileNationality] == "Int"

El Control Flow quedará de la siguiente manera:



Con esto hemos finalizado el Control Flow, por lo que debemos realizar la funcionalidad de los Data Flow Clientes Nacionales Data Flow Task y Clientes Internacionales Data Flow Task. En ambos debemos agregar un Flat File Source en donde utilizarán las conexiones “Clientes Nacionales – Origen” y “Clientes Internacionales – Origen” respectivamente. Posteriormente debemos agregar un OLE DB Destination que utilizará la conexión ““localhost.Examples” antes creada.



Luego de unir ambos componentes arrastrando la flecha verde del Flat File Source al OLE DB Destination, debemos realizar el mapeo de los campos en éste último.

Cómo podemos ver ambos Data Flow son muy similares, excepto que en el de los clientes Nacionales no disponemos de la columna “Pais” y por lo tanto no podemos mapearla a la Tabla de la BD.



3. Ejecución del proceso y análisis de resultados
El siguiente y último paso será ejecutar el proceso. Si nos paramos sobre el Control Flow de modo tal de ver el Foreach y todo su contenido y ejecutamos el proceso (Presionando F5) veremos cómo según sea el fichero que se está procesando correspondiente a clientes Nacionales o Internacionales, la ejecución se destinará a uno u otro Data Flow de acuerdo a que condición cumpla la variable varFilenationality obtenida.



Si analizamos los datos de la tabla TablaClientes podemos ver que se han importado correctamente los datos y la diferencia entre los clientes Nacionales e Internacionales es que estos últimos poseen un País, mientras que los nacionales tienen el valor NULL en ese campo.

Espero les haya sido de utilidad mi ejemplo y no duden en escribir comentarios ante cualquier duda o inquietud.

8 comentarios:

luru32 dijo...

Hola Miguel, es bueno tener en la web información sobre SSIS en español ya que nos ayuda mucho a entender y comprender mejor esta poderosa herramienta. Mi pregunta es la siguiente : Como hago para escribir variables dentro de un Component Script en un Data Flow, me he cansado de probar por aqui y por alla de muchas maneras y no he podido hacerlo. Gracias y saludos

luru32 dijo...
Este comentario ha sido eliminado por el autor.
Miguel A. Ciacci dijo...

Hola luru32, antes que nada perdón por al demora en responder pero he tenido unos días complicados de trabajo y estudio. Respondiendo tu pregunta, debes crear la variable en en el Scope que necesites (a nivel de package o el que creas necesario) como lo haces normalmente y luego desde el script en el Data Flow puedes instanciarla y manipular su valor. Puedes ver un ejemplo en este mismo Blog en el siguiente link http://mciacci.blogspot.com/2008/04/uso-de-precedence-constraint-para.html

Espero te sea de utilidad mi respuesta y en caso contrario avisame y lo seguimos analizando.
Saludos

Enrique dijo...

Hola Miguel, Muchas gracias por la atencíon, voy a verificar lo que me dices! la verdad fue una respuesta inmediata!!!
Lo que deseo hacer posteriormente a generar el archivo de salida (.xls) es:

- Empaquetarlo (el archivo que se genera es de 4 MB y no veo en el toolbox algo que me permita hacerlo)
- Enviarlo a una dirección de correo electrónio.

Todo de manera automática, tienes por ahí algún ejemplo que me pueda
apoyar en esta actividad?

Saludos y mil gracias por la atención.

Miguel A. Ciacci dijo...

Buenas Enrique, no tengo ningún ejemplo con lo que mencionas aquí pero tal vez te sea de ayuda lo siguiente que voy a escribir...

- Si con empaquetado te refieres a comprimir (ZIP, RAR, etc.) no conozco como puede hacerse, y tengo serias dudas de que pueda hacerse desde SSIS.

- Respecto a enviar un mail con estos ficheros deberías usar el componente "SEND MAIL TASK" que se encuentra en el Control Flow. Al editar este control puedes definir a quien enviarlo, el Servicio SMTP, los ficheros adjuntos, etc

Espero te sea de ayuda esto que te digo, caso contrario avisame y lo analizamos con más detenimiento. Saludos!

AlexH dijo...

Hola que tal Miguel, de antemano agradezco la aportacion de instruirnos a los que no sabemos!!! Como le puedo hacer para que de manera dinamica me genere un archivo txt utilizando la fecha del dia de obtención de información, y la clave de la empresa que viene en uno de los campos es decir EmpresaDDMMYYYY_ClaveEmpresa.txt, ya cuento con la extraccion solo me falta definir de manera dinamica el nombre.

Unknown dijo...

Hola Miguel Muchas Gracias Por la Información, tengo un problema que no he podido resolver: Como puedo hacer para llevar a un campo de mi base de datos ademas de las filas de un excel el nombre de archivo procesado en ese momento?

Agradezco muchisimo tu ayuda.

Saludos!

Unknown dijo...

Hola Miguel Muchas Gracias Por la Información, tengo un problema que no he podido resolver: Como puedo hacer para llevar a un campo de mi base de datos ademas de las filas de un excel el nombre de archivo procesado en ese momento?

Agradezco muchísimo tu ayuda.

Saludos!