No es algo que haga habitualmente, pero en casi todos los clientes termino codificando algún script (en VB.NET lo siento por los de c#) y como hace mucho que no escribo nada, vamos a volver a la carga con este tema.

Dentro de los paquetes de SSIS hay varios sitios donde podemos incluir tareas de script, si bien el contenido va a ser código generado por nosotros, el objetivo y la forma de tratarlos es distinta, pero principalmente podemos distinguir entre scripts dentro de un flujo de datos y las scripts que están fuera de un flujo de datos.

Los que están fuera de un flujo de datos son seguramente más fáciles de entender ya que no deja de ser un «trozo» de código que va a ejecutar una tarea concreta dentro de nuestro flujo de control y que podemos considerar como una mini aplicación dentro de nuestro paquete. Además esas tareas aceptan depuración y podemos ver qué ocurre mientras se ejecuta de una manera sencilla tal y como están acostumbrados los buenos desarrolladores de código. Sin embargo los que están dentro de los flujos de control tienen sus propias singularidades que son las que quiero contar:

  1. De primeras, no admiten depuración, una vez que se ejecuta el flujo de datos donde están contenidos, no hay manera de hacer una depuración de código, así que la única manera de ver que contiene las variables que hemos definido dentro es a fuerza de MsgBox (que comentaremos una vez hayamos asegurado que el código funciona como esperábamos)
  2. Admiten tanto código VB.NET como C#, pero una vez se ha elegido uno de los dos lenguajes, ya no puedes volver atrás.
  3. Puede actuar de tres maneras distintas, como un origen de datos, como una transformación o como un destino:

    1. Si es un origen de datos, en nuestro componente tendremos que definir un conjunto de columnas en un flujo de salida y por código iremos generando las filas que van a alimentar el resto del flujo de datos.
    2. Si es un destino de datos, solo tenemos que definir la entrada a partir del flujo de datos que vaya a recibir.
    3. Si es una transformación de datos, una vez definidos los campos de la entrada en función del flujo que recibe, hay que definir una salida. La definición de esa salida es clave en cómo se va a comportar nuestro componente.
      1. Si directamente enlazamos la salida con la entrada, el objeto se comportará de forma síncrona y según entren las filas, serán tratadas por el script y se lanzarán al buffer de salida.
        1. Sin embargo, si eliminamos la referencia del buffer de entrada (como se ve en la pantalla de abajo), será el script el encargado de recoger las filas de entrada, tratarlas y definir cuando hay una fila lista para ser lanzada al buffer de salida. Se genera por tanto una tarea asíncrona.  

           

          En estos casos tenemos que definir que columnas van a componer el buffer de salida, ir avanzando fila a fila por código y generar la fila en el buffer de salida.

          En este ejemplo vamos a contar el número de filas que pertenecen a una misma organización y tiempo. La transformación recibirá un flujo de datos ordenado por fecha y organización e incluiremos el siguiente código:

          Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer) 
          ' 
          ' Add your code here 
          ' 
          Dim iSubtotal As Integer 
          Dim iPrevTime As Integer 
          Dim iPrevOrganization As Integer 
          
          
          'Inicializamos las variables con el valor de la primera fila del buffer de entrada 
          iSubtotal = 1 
          iPrevOrganization = Row.OrganizationKey 
          iPrevTime = Row.TimeKey 
          
          
          'Mientras haya filas en el buffer de entrada avanzamos 
          While Row.NextRow 
          
          
          
          
          If iPrevOrganization = Row.OrganizationKey And iPrevTime = Row.TimeKey Then 
          
          
          'Si la fila pertenece al mismo tiempo y organización contamos la fila y avanzamos el buffer 
          'hasta la siguiente fila 
          iSubtotal = iSubtotal + 1 
          Row.NextRow() 
          
          
          Else 
          'Si hemos cambiado de tiempo y organización, nos quedamos con los nuevos valores para 
          'chequear el cambio en los datos 
          iPrevOrganization = Row.OrganizationKey 
          iPrevTime = Row.TimeKey 
          
          
          'Creamos la fila con la información del número de filas por tiempo y organización 
          SalidaAgrupadaBuffer.AddRow() 
          SalidaAgrupadaBuffer.TimeKey = Row.TimeKey 
          SalidaAgrupadaBuffer.OrganizationKey = Row.OrganizationKey 
          SalidaAgrupadaBuffer.NumeroFilas = iSubtotal 
          
          
          End If 
          
          
          End While 
          
          
          'Cerramos el buffer de salida para notificarlo al flujo de datos 
          SalidaAgrupadaBuffer.SetEndOfRowset() 
          End Sub 
          
          

          En los visores de datos, vemos como recibimos un conjunto ordenado de filas donde se repiten los datos de tiempo y organización y en el visor de datos de la salida vemos que solo tenemos un registro por combinación de clave de tiempo y organización con el número de registros.