Dentro de las múltiples tareas preconstruidas que nos provee SSIS, tenemos la posibilidad de trabajar con tipos de datos blobs (binarios). Estas operaciones consisten básicamente en insertar estos objetos en la base de datos (Import Column) o bien exportarlos (Export Column) para que estén disponibles en el sistema de archivos.
Exportar estos datos es sencillo: una vez seleccionado del origen la tabla que contiene un campo image (por ejemplo), añadimos la transformación Export Column al flujo de datos. Su editor solicitará, obligatoriamente, seleccionar la columna que contiene el campo binario de la tabla que previamente se ha configurado en el origen de datos (desplegable Extract column) y la ruta (incluyendo el nombre y extensión del archivo) en donde queremos depositar el objeto.
Como vemos, como mínimo tan sólo tres objetos necesitamos en nuestro paquete SSIS para tener disponible en el sistema de archivos aquellos tipos de datos binarios que están almacenados en nuestra base de datos: un Data Flow, un origen OLE DB Source y una transformación Export Column. Tan sólo si nuestra tabla no contiene la ruta completa, o bien queremos modificarla, tendremos que añadir otra transformación Derived Column para crear la expresión que contenga dicho valor.
Podéis probar esta transformación estableciendo la tabla Production.Document de la base de datos AdventureWorks, la cual contiene la columna Document que es del tipo de datos VARBINARY(MAX)
Sin embargo, cuando queremos ejecutar la tarea contraria, esto es, importar una serie de ficheros desde el sistema de archivos a nuestra base de datos (tal vez una operación más común que la anterior), nos encontramos con varias limitaciones. El primer problema que nos encontramos es que no tenemos, de la lista de orígenes de datos disponibles, ninguno que nos sirva, ya que no hay ningún origen que sea del tipo “archivo binario”; además, aunque lo tuviéramos, tampoco nos serviría, ya que lo que necesita como entrada esta transformación es la ruta en donde se encuentra el fichero, no el fichero propiamente. Esto nos obliga a tener un origen de datos que contenga la lista de los archivos que queremos importar (un fichero de texto, una tabla de una base de datos, una hoja de cálculo…).
Otro problema que nos encontramos es que el editor de esta transformación no es muy sencillo: nos obliga a realizar una operación para, a partir de las filas de entrada (Input Rows), crear una columna de salida de tipo binario y conectarlo con la columna de entrada a partir del ID de la primera. Esto, que parece casi un trabalenguas, hace que la configuración de la transformación sea un tanto engorrosa.
Si nos fijamos en las imágenes, se ha tenido que crear una columna dentro del nodo Output Columns pulsando en el botón Add Column. Una vez hecho esto, se anota el valor de la propiedad ID de esta columna (resaltado en la imagen) y se escribe en la propiedad FileDataColumnID.
Un problema menos
Realmente el problema que nos limita más es el primero, puesto que el segundo inconveniente es más una cuestión de acostumbrarse a crear la columna de salida, anotar el ID, escribirlo en la otra propiedad… Sin embargo, la necesidad de usar un almacenamiento transitorio para almacenar el nombre de los archivos que vamos a tratar es lo que va a hacer que nuestro paquete sea más complicado de mantener, más lento y dependiente de más recursos externos.
Una de las mayores ventajas de SSIS con respecto a los DTS es la posibilidad de extender la funcionalidad que trae a través de programación. En el caso que nos ocupa, la idea es tener un origen que nos devuelva directamente la ruta de un fichero; si podemos combinarlo con la lectura del contenido de un directorio, mejor que mejor.
Lo segundo lo tenemos con el contenedor ForEach Loop; lo primero mediante la transformación Script Component dentro de un Data Flow. Sigamos entonces los siguientes pasos:
- Añadir un ForEach Loop Container dentro del flujo de control. Dentro de él, una tarea Data Flow. Indicamos cualquier directorio que contenga un par de archivos, y marcamos la opción Fully Qualified en Retrieve file name. En Variable Mappings crearemos una variable de nombre fichero y la seleccionaremos del desplegable
- En el flujo de datos, añadiremos un objeto de tipo Script Component, le indicamos que es de tipo Source. Creamos una nueva salida a la que llamaremos Salida (originales, ¿verdad?), añadiéndole una columna de salida a la que llamaremos fichero, de tipo string[DT_STR] y longitud 500. Nos tiene que quedar así:
- En la opción Script, añadiremos el siguiente código dentro del método CreateNewOutputRows():
Dim file As New FileInfo(Me.Variables.fichero.ToString())
With Me.SalidaBuffer
.AddRow()
.fichero = Me.Variables.fichero.ToString()
End With
- Cerramos la ventana de código y el editor de la transformación, volviendo al flujo de datos, en donde añadiremos un control de tipo Import Column y un destino OLE DB que por ejemplo, se conecte a TempDB de nuestro SQL Server 2005 de pruebas. Enlazamos el componente de script con la transformación y vamos directamente a la pestaña Input and Output Properties; en el desplegable Import Column Output añadimos una columna de salida a la que llamaremos doc y será de tipo image[DT_IMAGE]; apuntamos el valor de la propiedad ID para ponerlo en la propiedad FileDataColumnID de la columna de entrada que llamamos fichero. Es decir, tendrá que quedar algo parecido a lo que las imágenes muestran (el ID será diferente en el vuestro)
- Añadimos como destino una tabla creada a tal efecto en TempDB, a la que podremos insertar tanto la ruta completa donde se encontraba el archivo (columna fichero) como el archivo propiamente dicho (columna doc):
Ahora no tenéis más que ejecutar vuestro paquete para comprobar que se han cargado todos los archivos que había en el directorio indicado, sin necesidad de un almacenamiento temporal.
Vemos cómo la funcionalidad de importar archivos a nuestras bases de datos mediante SSIS se ha visto ampliada. Sin embargo, si consiguiéramos tener un origen en el flujo de datos que fuera capaz de realizar estas acciones sin necesidad de usar un contenedor, sería genial… pero esto lo dejaremos para otra entrada de este blog. ¡¡¡Permaneced atentos!!!