Leyendo ficheros de texto desde SQL Server Integration Services
Posted by Miguel Egea | Posted in SQL Server Integration Services, Tutoriales | Posted on 25-10-2011
0
Vamos a ver un ejemplo de como leer ficheros de texto desde SQL Server Integration Services. Huyendo un poco de los ejemplos típicos vamos a hacer un paquete de SSIS que corrija la sincronización de los ficheros .srt de subtitulos. Muchos reproductores de video pueden subtitular cualquier contenido multimedia a partir de ficheros de extensión srt. Estos ficheros realmente son texto plano con un formato como este.
Nota: Como podeis ver mi entorno siempre está en Inglés, en mi caso hay dos motivos, primero trabajo en una compañía internacional, en la que el inglés es la lengua “común”. Segundo, es innegable, que en el mundo de la informática el inglés es lo más universal, no me acaban de convencer las traducciones, no porque estén mal sino porque a fuerza de costumbre no encuentro nada cuando el entorno está en el idioma de Cervantes. Mis disculpas a los más puristas.
1
00:00:01,968 –> 00:00:04,835
Ejemplo de texto 1
2
00:00:04,938 –> 00:00:08,237
Ejemplo de texto 2
En resumen se trata de una linea indicando el orden, otra indicando el intervalo de tiempo separado por –> y una tercera que es el texto. Nuestro ejemplo tratará de crear un paquete de SSIS que cambie (adelantando o atrasando) la sincronización de estos ficheros .srt.
Para comenzar lo que haremos será crear un nuevo paquete de SSIS. Los ejemplos que vais a ver están hechos con la CPT3 de SQL Server 2012 , AKA Denali.
Colocaremos un Data flow Task. En entorno nuevo es realmente muy atractivo, el zoom se ve muy claramente, las barras de tareas están muy mejoradas, incluso la ayuda parece más adecuada al comienzo con SSIS
Renombraremos la caja del data flow task con un nombre más descriptivo, recordad que esto es bastante importante. Si lo hacemos bien los paquetes serán prácticamente auto-documentados y eso será realmente interesante, particularmente transcurrido algún tiempo desde el comienzo.
Despues, pulsaremos botón derecho sobre la superficie de Connection Managers y crearemos una nueva conexión a fichero de texto pulsando sobre “New Flat File Connection”.
Ahí simplemente especificaremos un fichero del formato que estamos tratando, en mi caso demo.crt como puede observarse en la siguiente figura. Notese que he tocado la propiedad “column names in the first data row” porque no es así.
En nuestro caso las columnas como tal no existen, pero si tendremos 4 tipos de filas, los casos más normales quizá los campos vengan separados por comas o por puntos y comas, o por cualquier caracter. Cualquier escenario común se podrá manejar tocando unas pocas propiedades. Nuestro caso, en el que vienen mezcladas cosas hemos de probar a distinguir cada una de las lineas. Al pulsar en la segunda pestaña veremos una pantalla como la siguiente
Esto nos dice que efectivamente cada línea tendremos que tratarla de una forma distinta. A continuación vamos a poner un conector a este fichero de texto como origen de datos siguiendo el wizard de SQL Server 2012
En nuestro caso seguiremos el wizard, elegiremos fichero de texto plano y el origen de datos que acabamos de crear. Eso nos dejará un componente origen de datos de texto que veremos en las siguientes imágenes. En nuestro caso además le cambiaremos el nombre, ya sabéis con el objeto de que sea autodescriptivo.
En nuestro caso, lo único que queremos hacer es modificar las líneas que tienen fecha y horas desplazandolas un tiempo hacia adelante o hacia atrás.
Las columnas que tienen este dato tienen un formato como este
00:00:01,968 –> 00:00:04,835
Ambas horas han de ser desplazadas.
Para poder hacer el desplazamiento necesitaremos dos cosas
- Identificar que es una línea de tipo rango de tiempos
- Añadir o quitar el tiempo determinado
Para poder añadir o quitar un tiempo variable, usaremos eso.. variables. Vamos pues a añadir una variable “desplazamiento”. Para ello pulsaremos con el botón derecho del mouse sobre la superficie del dataflow task y pulsaremos la opcion “variables”. A continuación pulsaremos el botón añadir variable , que es el resaltado en amarillo en la siguiente figura.
Nombraremos a la variable como estimemos oportuno (en nuestro ejemplo desplazamiento) y le daremos como tipo de datos int y como Valor el desplazamiento que queremos obtener (milisegundos) . El objeto debe tener como Scope (alcance) el necesario para que funcione en nuestro ambiente. El scope es el equivalente a donde se ven las variables (todo el paquete, este objeto, el flujo de trabajo.. etc). Nuestra variable ha de quedar como puede verse en la siguiente figura.
El siguiente paso será distinguir las líneas que son de tipo desplazamiento. Si lo es, entonces simplemente sustituiremos el valor por el incremento que necesitamos en ambos casos.
Para distinguir estos casos usaremos la funcion FindString, que localiza la posición de una ocurrencia. Esta condición
FINDSTRING([Column 0],”–>”,1) == 0
Nos daría verdadero solamente si la cadena no se encuentra. Si la cadena se encuentra entonces tendremos que incrementar la función.
Para incrementar desplazamiento sobre la fecha hora hay que hacer lo siguiente :
- Separar la hora de comienzo
- Convertirla en fecha hora
- Incrementarla
- Convertirla en texto
- Separar la hora de fin
- convertirla en fecha hora
- incrementarla
- convertirla en texto
- Unirla
Todas estas operaciones se podrían hacer en una sola expresión, pero esto seguramente nos haría muy compleja esa expresión, en su lugar, y con el fin de mejorar la claridad lo vamos a hacer en varios pasos
Paso 1. Crear dos columnas con el texto desde hasta.
Para desde usaremos la siguiente expresión
FINDSTRING([Column 0],”–>”,1) != 0 ? LEFT([Column 0],FINDSTRING([Column 0],”–>”,1) – 1) : “00:00:00.000″
Entendida significa,
si la posición que devuelve findstring es distinta de cero, (es una de las que nos interesan)
Empezando por la izquierda quedate los caracteres hasta que empieza el “—>”
si no
pon un “00:00:00.000”
Un caso equivalente es el de la expresión hasta
FINDSTRING([Column 0],”–>”,1) != 0 ? SUBSTRING([Column 0],FINDSTRING([Column 0],”–>”,1) + 3,100) : “00:00:00.000″
sla posición que devuelve findstring es distinta de cero, (es una de las que nos interesan)
Empezando por donde está el “—>” quedate con todos los caracteres hasta el final
si no
pon un “00:00:00.000”
Así queda el derived column component que tiene estas expresiones
Ambas expresiones devuelven un string.. y no se puede operar con esos strings como si fueran fechas, así que vamos a añadir un componente adicional que convierta a fecha esos strings y les añada el desplazamiento
La formula que usaremos será la siguiente para desde
DATEADD(“Ms”,@[User::Desplazamiento],(DT_DBTIMESTAMP)(DT_DBTIME2,3)REPLACE(Desde,”,”,”.”))
Es decir en un solo paso convertirmos a fecha, añadimos los milisegundos que necesitamos y guardarmos en una nueva variable
El motivo de que la expresión sea tan compleja es para asegurarnos que no tenemos molestos problemas de conversión. Pasando por DT_DBTIME2 nos aseguramos de convertir adecuadamente el formato que recibimos “00:00:00,000”, como la coma que recibimos esperamos sea un punto.. pues hay que sustituirla. Despues convertimos a D_DBTIMESTAMP para poder hacer la operación de suma de milisegundos y por último sumamos esos milisegundos.
La figura muestra como queda la cajita de derived column
Conseguido esto ahora hemos de deshacer el camino, deshacer el camino implica convertir esto a un formato tal que así .
00:00:01,968 –> 00:00:04,835
Aunque también podría hacerse en un solo paso, vamos a usar varios para que se vea con más claridad. La expresión que usaremos será la siguiente
SUBSTRING((DT_WSTR,30)[Desde Fecha],12,12)
Primero convertimos a string, esto nos da el formato 2011-10-25 00:00:15.988 y de este nos quedamos con 12 caracteres empezando en la posición 12, es decir.. el mismo formato de origen. Así queda el cuadro derived column.
Por último usaremos una nueva columna derivada para unir ambas tal y como estaba la original, la fórmula será, y aprovecharemos para sustituir la actual con esta expresión en el caso que sea la columna que esperamos.
FINDSTRING([Column 0],”–>”,1) != 0 ? [Desde Texto] + ” –> ” + [Hasta Texto] : [Column 0]
Así queda el componente
Por último, grabamos nuestro fichero de salida, para eso creamos una nueva conexion a archivos de texto y seguimos el asistente como destino.
Configuramos el fichero de la misma forma, excepto que en advanced añadiremos nosotros la columna de forma manual como string de 200 caracteres. Despues en los destinos buscaremos el flat file dstination y lo enchufaremos para que funcione. Entraremos en mappings y conseguiremos mapear la columna 0 del origen a la columna 0 del destino
Por último vamos a permitir que tanto el fichero de origen como el de destino puedan ser expresados por parámetros, usando variables. Así pues crearemos dos variables, origen y destino de tipo string
Estas variables nos serviran para ponerlas como expresión en las cadenas de conexion. Lo que haremos será poner en expresiones que el connection string se tome desde una variable, como puede verse en la imagen siguiente
Haremos la misma operación con el destino, quedará tal que así
Nuestro paquete finalmente quedó así
















