Monday, December 14, 2009

Mapa con Report Builder 3.0 Maps y SQL Server 2008

Os adjunto un video de una demo que realicé en mis últimos eventos sobre Business Intelligence. Se trata de la creación de un mapa de ventas por territorio hecho con Report Builder 3.0 R2 CTP y una fuente de datos SQL Server 2008. En unos sencillos pasos podemos tener un informe para visualizar sobre un mapa los resultados de ventas de nuestra empresa. Más fácil imposible!!!




Wednesday, December 9, 2009

Artículo publicado en MSDN

Hola a todos.
Esta mañana me han comunicado que mi artículo sobre procesamiento de dimensiones en SSIS había sido publicado en MSDN España. Podéis echarle un vistazo al mismo en:

http://msdn.microsoft.com/es-es/ee815809.aspx


Friday, December 4, 2009

SQL Server 2008 R2

Hola a todos.
Hace unos días se liberó la CTP de Noviembre de SQL Server 2008 R2. Podéis acceder directamente mediante este link:
http://www.microsoft.com/sqlserver/2008/en/us/R2Downloads.aspx
Adicionalmente podéis descargar el complemento Report Builder 3 con nuevas y espectaculares funcionalidades. El acceso directo a la descarga es:
http://download.microsoft.com/download/5/4/D/54D3A5E3-71EF-45B7-BA9D-02F0A7C4ABB7/ReportBuilder3.msi
Os recomiendo instalaros Office Excel 2010 con Powerpivot para probar a fondo las nuevas capacidades de esta versión de Excel. Powerpivot es capaz de conectar a casi cualquier fuente de datos e integrar la información en la hoja de cálculo. Con los datos cargados en memoria, el usuario es capaz de definir relaciones entre los datos recuperados y construir estructuras de cálculo complejas como si de un cubo se tratara.
Puedes descargar la beta 2 de Office Excel en el mismo link que la CTP de SQL Server 2008 R2.

Wednesday, October 28, 2009

Herramienta de deploy personalizada con SSIS

Hola a todos.
Demasiado tiempo sin publicar, supongo.
Bueno, ya estoy de vuelta otra vez, ahora con una herramienta muy útil si estás usando paquetes SSIS con archivos de configuración y estás intentando hacer un deploy en un servidor de producción.
Imagínate que estás guardando la información de una cadena de conexión sin seguridad integrada, es decir, usando autenticación SQL Server, en un repositorio de código fuente (Team System o Source Safe). No te quedará más remedio que proporcionar la contraseña en la cadena de conexión para conectar a las distintas fuentes.
No podrás almacenar la contraseña en el paquete a menos que utilices cifrado, pero no es una buena idea ya que no queremos ni introducir una contraseña cada vez que abrimos el paquete en Visual Studio, ni cifrar con la clave del equipo porque no vamos a ser capaces de desplegar en producción después.
La manera más sencilla de solucionar este problema es incluir la contraseña en las cadenas de conexión guardadas en la configuración de SSIS, como por ejemplo en fichero de configuración. Puedes sobreescribir el archivo de configuración con el bloc de notas para incluir la contraseña sin que Visual Studio te la quite.
Ahora el problema es que cuando se haga deploy en producción y los servidores de desarrollo no estén visibles desde este entorno, recibiremos un timeout utilizando el wizard de instalación de paquetes de SSIS.
Bien, he desarrollado una pequeña herramienta winforms para instalar los paquetes sin validación que facilitará mucho el proceso de deploy, ya que esta no realiza ningún tipo de validación evitando así el problema del timeout.
Puedes descargar el proyecto completo y la herramienta desde aquí.

Monday, April 27, 2009

Limpieza de datos (Data Cleansing) con Script en SSIS

Hola chicos.
Muchas veces he necesitado hacer frente a información realmente sucia, poblada con cadenas en blanco, valores nulos y fechas futuras. La mayoría de las veces he tenido que limpiar estos valores en varios flujos de datos y varios paquetes. Podemos hacerlo fácilmente incluyendo un componente 'Column Transformation', pero tendríamos que declarar la función de transformación para cada columna que queramos limpiar.
Un enfoque diferente sería utilizar el componente de script para cubrir cada columna que deseáramos limpiar de forma automática, a través de la reflexión de .NET.
En el componente de script tendremos que seleccionar las columnas de entrada que hay que limpiar. A continuación declaramos un bucle que iterará para cada columna y realizará un llamada a la función de limpiar valor, dependiendo del tipo del valor de la columna.
En el ejemplo de código siguiente, se limpia la cadena de columnas con valores en blanco, y se reemplazan las fechas futuras con un null:


Imports System
Imports System.Data
Imports System.Math
Imports System.Reflection
Imports Microsoft.SqlServer.Dts.Pipeline
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

Public Class ScriptMain
Inherits UserComponent

Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
Dim str As String
Dim obj As Object
Try
Dim p As PropertyInfo
For Each p In Row.GetType().GetProperties()
'First check, null properties
If p Is Nothing Then
Continue For
End If
'Second check, null values
If p.GetValue(Row, Nothing) Is Nothing Then
Continue For
End If
'Second check by types
If p.PropertyType Is GetType(String) Then
p.SetValue(Row, CleanString(p.GetValue(Row, Nothing).ToString()), Nothing)
End If
If p.PropertyType Is GetType(DateTime) Then
If CType(Row.GetType().GetProperty(p.Name() + "_IsNull").GetValue(Row, Nothing), Boolean) = True Then
Continue For
End If
obj = CleanDate(p.GetValue(Row, Nothing))
If obj Is Nothing Then
Row.GetType().GetProperty(p.Name() + "_IsNull").SetValue(Row, True, Nothing)
Else
p.SetValue(Row, obj, Nothing)
End If
End If
Next
Catch e As Exception
'Do Nothing
End Try
End Sub

Public Function CleanString(ByVal str As String) As String
If str.Trim() = "" Then
Return Nothing
End If
Return str
End Function

Public Function CleanDate(ByVal obj As Object) As Object
Dim dt As DateTime
dt = CType(obj, DateTime)
If dt > DateTime.Now Then
Return Nothing
End If
Return obj
End Function

End Class


Sunday, March 22, 2009

Extracción de datos con marca de tiempo (Timestamp Data Extraction) con SSIS

Hola a todos.
Tal vez hayas oído hablar de los diferentes métodos de extracción de datos que existen en el mundo ETL: Timestamp, fecha de modificación, bits de columna, Checksum, Triggers, o incluso con SQL Server 2008 tenemos Change Data Capture o la instrucción MERGE.
Hoy voy a explicar una solución para Timestamp y la manera de aplicarlo con SSIS. En primer lugar tenemos que entender qué tipo de datos es Timestamp y cómo usarlo.
El tipo de datos Timestamp se compone de un conjunto de bytes que nos ayuda a identificar las filas que se han modificado. Cuando se agrega una columna TIMESTAMP en una tabla (sólo se permite una por tabla), cada fila insertada o actualizada se marca con un nuevo valor incremental de Timestamp. Sin embargo, se debe tener en cuenta que no es posible convertir un valor de Timestamp a algo parecido a una fecha, como mucha gente piensa. Es sólo una secuencia de bytes, un número hexadecimal que crece constantemente.

Lo primero es tener una tabla de control para guardar el último Timestamp procesado en cada ejecución de nuestro proceso de ETL. De esta manera, buscaremos en cada ejecución sólo las filas que se han modificado desde la última vez que ejecutamos.

Vamos a ver cómo hacerlo con un ejemplo.
Tendremos una tabla de clientes de origen, en la que hemos añadido una columna timestamp. También tendremos una tabla de clientes de destino y una tabla de control para almacenar el último Timestmap leído de la tabla de origen. Las tablas deberían tener este aspecto:

Ahora vamos a diseñar el paquete SSIS. Con el fin de no perder ninguna fila, debemos recuperar los timestamps al principio, y almacenarlos en dos variables de SSIS. De esta forma definimos el intervalo de filas que vamos a leer durante la ejecución del paquete, y no importará si mientras corre el paquete se modifican más filas. Las dos SELECTs son las siguientes:
• La primera recupera el timestamp de la última ejecución, almacenado en la tabla de control. Almacenaremos el valor del resultado en la variable de SSIS TimestampTo.


SELECT LastReadTimestamp FROM LastReadTimestamps WHERE TableName = 'customers'


• La segunda SELECT recupera el valor máximo de todos los timestamp de la tabla de clientes de origen. El valor lo guardamos igualmente en una variable de SSIS llamada TimestampFrom.


SELECT convert(varchar(20),convert(numeric(20,0),max(timestamp) + 0)) AS timestamp FROM dbo.Customers


En el siguiente paso de flujo de control diseñaremos el flujo de datos. Con una tarea de 'Data Flow Task' moveremos las filas modificadas desde la fuente a la tabla de destino. Para ello, utilizaremos las dos variables como parámetros en el componente 'OLEDB Source Component'. La sentencia SELECT debería tener este aspecto:


SELECT CustomerID,Name,Surname,Location
FROM Customers
WHERE convert(numeric(20,0),timestamp + 0) > ? AND convert(numeric(20,0),timestamp + 0) <= ?



Tenemos que convertir el timestamp a un valor numérico para compararlo con el parámetro. SQL Server no es capaz de convertir directamente de timestamp a un numérico, pero poniendo un "+0" después del nombre de la columna se resuelve el problema rápidamente.

Una vez tenemos los valores modificados que puede sincronizar fácilmente la tabla de destino, por ejemplo con un componente SCD. El diseño del flujo de datos debería tener este aspecto:

Finalmente, nos quedaría almacenar el timestamp del último cliente leído en la ejecución, que es exactamente el valor almacenado en la variable TimestampTo. Guardaremos el valor mediante una tarea de tipo "Execute SQL Task" con un parámetro:


UPDATE LastReadTimestamps
SET LastReadTimestamp = convert(numeric(20,0), ?)
WHERE TableName = 'Customers'



Con este enfoque se puede mejorar fácilmente el rendimiento de nuestro flujo de datos de SSIS debido a que sólo se procesan las filas que se han modificado desde la última ejecución. No hay ningún tipo de trabajo extra, todas las filas que se procesan sabemos con certeza que han sido modificadas de una u otra forma.

Espero que hayan encontrado interesante este artículo.