Mostrando entradas con la etiqueta Variables. Mostrar todas las entradas
Mostrando entradas con la etiqueta Variables. Mostrar todas las entradas

jueves, 18 de abril de 2013

SSIS Básico: Guardar valor de columnas en una variable

 

En relación a uno de los comentarios que me han dejado en el post SSIS Básico: Ajustando la longitud de una columna, volvemos a la carga con pequeño how-to de como guardar el valor de una columna en una variable dentro de un Data Flow a utilizando un Script component.

Para poneros en situación, voy a utilizar una tabla que guarda tweets publicados con ciertas palabras, y guardaremos en la variable el último usuario que haya publicado en función de la fecha  del tweet registrada en la columna Created_at.

Primero debemos contar con la variable en la que necesitamos guardar el valor, para este ejemplo he creado la variable VariableCadena, con ámbito de paquete para poder utilizarla en el Control Flow o subsiguientes Data Flows:

image

Dentro del Data Flow en el que vamos a registrar el valor de alguna columna en la variable, añadimos un Script component en modo transformación:

image

En la configuración del componente, en la sección Input columns, seleccionamos la columna desde la que queremos obtener el valor, y cualquier otra que necesitemos si la lógica de asignación del valor tiene más dependencias. Para este ejemplo vamos a utilizar las columnas UserName y Created_at del flujo de datos:

image

Nos movemos a la sección Script y añadimos nuestra variable a la lista de variables con acceso de escritura.

image

Pulsamos el botón Edit Script para escribir el código necesario (ejemplo en C#). Algo que debemos tener en cuenta es que no se permite la escritura de valores en variables fuera del método PostExecute(), por lo que nos tendremos que apoyarnos en variables de la clase ScriptMain para poder dar salida a nuestra variable de paquete.

Otro detalle a comentar es el método <nombreInput>_ProcessInputRow, que se ejecutará para cada una de las filas que provea el flujo de datos conectado a este componente.

Con esto en mente, escribimos el siguiente código:

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
//variables de apoyo para la lógica
string UserName = string.Empty;
DateTime Created_at = DateTime.MinValue;

public override void Input0_ProcessInputRow(Input0Buffer Row)
{
//evaluamos si la fila actual tiene una fecha mayor a la registrada por la última fila
if (Row.Createdat > this.Created_at)
{
//asignamos el nombre del usuario a la variable interna
this.UserName = Row.UserName;
this.Created_at = Row.Createdat;
}
}

public override void PostExecute()
{
base.PostExecute();
//asignamos el valor de la variable interna a la variable de paquete
this.Variables.VariableCadena = this.UserName;
}
}

Como habeis comprobado, utilizamos la variable interna UserName para guardar el valor que queremos asignar a la variable de paquete en el método PostExecute().


Otra nota importante: Dentro del mismo Data Flow no se puede acceder al contenido de la variable modificada. Cuando el proceso de ejecución entra en el Data Flow se bloquea el valor que tuviera la variable en el momento del evento PreExecute(), como se muestra en el post SSIS Utilizando el RowCount. Recordad que a la variable de paquete le asignamos el valor en el evento PostExecute().


Sin embargo, el nuevo valor esta diponible a partir de entonces y por tanto para cualquier tarea que se ejecute a continuación. Podemos mostrar el valor de la variable en un Script task desde el Control Flow con propósitos didacticos, aunque este tipo de mecanismos se suele utilizar para luego pasar como parámetro a filtros en consultas en otro Data Flow o Execute SQL…


image


 





domingo, 24 de junio de 2012

SSIS Cargando archivos Excel

 

Siempre hay quienes comienzan a hacer algo nuevo y este post está dedicado a estas personas, en concreto a Claudio. Un compañero de los foros de Integration Services en castellano que se preguntaba como podía conseguir resolver su proceso mediante paquetes ETL de SSIS.

 

Escenario

el asunto es que yo tengo una consulta, esta consulta me trae unos datos los cuales los tengo que poner en un excel con la fecha de la generacion y enviarlo a una persona, la idea es crear un paquete que permita mediante algun proceso crear el archivo excel con el nombre del dia(ejemplo ventas_19-06-2012.xls), mas que nada seria para automatizar un par de tareas que debo realizar diariamente

 

Una Solución

Por que siempre hay varios caminos para llegar al mismo sitio. Para este caso he sugerido utilizar una plantilla de libro Excel como destino de datos, que vamos a copiar con una tarea File System para generar un nuevo archivo con la fecha de la consulta que será el destino de los datos obtenidos mediante la misma (consulta)

Vamos con los detalles…

Es nuestro paquete ETL añadimos un DataFlow, con un origen OLEDB source con la consulta que vamos a realizar contra el origen de datos. Para esta entrada utilizaré la base de datos AdventureWorks para realizar esta consulta:

SELECT [ProductID],[Name],[ProductNumber],[MakeFlag],[FinishedGoodsFlag],[Color]
FROM [Production].[Product]

En el archivo Excel que vamos a utilizar como plantilla creamos las columnas necesarias para mapear con los datos de origen:

image

Hay que tener clara la versión de Excel a utilizar, dependiendo de esto podremos utilizar el componente Excel Destination (hasta Excel 2007) o nos veremos obligados a utilizar OLEDB Destination en caso de Excel 2010. En este caso la versión es 2007.

Añadimos un componente Excel Destination. Conectamos la salida de datos del OLEDB Source a la entrada del destino Excel y editamos este componente para establecer el archivo destino y el mapeo de datos.

Creamos una nueva conexión que apuntamos al archivo plantilla:

image

Una vez finalizada la conexión realizamos el mapeo de datos entre las columnas del origen de datos y el archivo Excel:

image

Y finalizamos la edición del componente de destino. Hasta ahora fácil, no hemos hecho nada especial para generar archivos dinámicamente en función de la fecha pero hemos conseguido establecer los metadatos que necesitan los componentes en el flujo de datos.

En las propiedades de este componente (en el panel de propiedades, F4 teniendo seleccionado el componente Excel Destination), hay que cambiar la propiedad ValidateExternalMetadata a false. Es importante este cambio para poder ejecutar el paquete sin que exista previamente el archivo sobre el que vamos a volcar los datos:

image

El siguiente paso es cambiar algunas propiedades en el administrador de conexión del archivo Excel, en concreto vamos a poner la atención en Delay Validation, que vamos a establecer a True. Observar la propiedad ExcelFilePath, que modificaremos más adelante mediante una variable que proporcionará el nombre de fichero para cada ejecución a través de Expressions:

image

Nos volvemos a la pestaña de ControlFlow y creamos una variable para generar el nombre del archivo en cada ejecución. Para esto hay que asegurarse de que tenemos seleccionado el lienzo y no el componente DataFlow que añadimos antes, para que el ámbito de esta variable sea del alcance de todo el paquete. Para acceder al panel de variables puede hacer clic derecho sobre el lienzo y seleccionar la opción variables. Crearemos la variable vNombreArchivo de tipo string y sin asignación de valor:

image

Seleccionamos la variable y pulsamos F4 para mostrar su panel de propiedades. En la propiedad EvaluateAsExpression seleccionamos el valor True y en Expressions vamos a añadir una expresión que conformará el valor de esta variable

image

En el editor de expresiones generamos una para construir un nombre de fichero en función de la fecha de proceso. Yo he utilizado la siguiente:

"C:\\Consultas2Excel\\Consulta_" + (DT_STR,20,1252) ( (DT_I8) (YEAR( @[System::StartTime] )) * 100000000 + MONTH(@[System::StartTime])*1000000 + DAY(@[System::StartTime]) * 10000 + datepart("hh",@[System::StartTime] ) * 100 + datepart("mi",@[System::StartTime] )   ) + ".xlsx"

image


Ya tenemos un nombre dinámico para nuestro fichero destino. Ahora solo falta que ese fichero exista y lo vamos a conseguir con una tarea File System Task que añadimos al ControlFlow y establecemos restricciones de precedencia, conectando la salida de ejecución correcta de File System Task con el DataFlow que ya teníamos:


image


Editamos la tarea File System para modificar sus propiedades. Lo primero es asegurar que la operación es Copy File. Establecemos los siguientes valores por propiedad






















PropiedadValor
OperationCopy File
IsDestinationPathVariableTrue
OverwriteDestination(evaluar la necesidad de sobreescribir el archivo de destino si existe en la operación de copia)
IsSourcePathVariableFalse
SourceConnection(Nueva conexión a nuestro archivo plantilla) c:\PlantillaDestino


image


En el panel de conexiones, buscamos la conexión a Excel que utiliza nuestro destino en el DataFlow y accedemos a las propiedades, en concreto Expressions y añadimos una expresión para la propiedad ExcelFilePath. Escribimos @[User::vNombreArchivo]


image


Y listo!


Ya tenemos un paquete que lee datos de una consulta y lo vuelca en un fichero Excel nuevo que genera en cada ejecución:








imageimage
 image


 


Conclusión


Como también vimos en la entrada SSIS Dinamizando propiedades de componentes, el uso de variables facilita en gran medida operaciones de asignación dinámica de propiedades de componentes, tareas, DataFlow, ControlFlow… Además, podríamos utilizar configuraciones de paquetes (en package deployment model) o parámetros y entornos (project deployment model) para exponer estas variables y asignarles valor previa ejecución del paquete.


Si tienes cualquier duda o quieres obtener el paquete ETL  desarrollado durante esta entrada, deja un comentario.

Entradas populares