<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4398803826831219104</id><updated>2011-09-17T13:33:35.817+02:00</updated><category term='64 bits Server'/><category term='Pipeline'/><category term='Seminar'/><category term='Microsoft'/><category term='TFS'/><category term='Performance Management'/><category term='SQL Server'/><category term='Deployment'/><category term='Lookup Component'/><category term='Office Excel'/><category term='MCP'/><category term='Powerpivot'/><category term='CPM'/><category term='Business Intelligence'/><category term='Best Practices'/><category term='Configuration'/><category term='Analysis Services'/><category term='Sensitive'/><category term='Sales'/><category term='Scripting'/><category term='Connection String'/><category term='SCD'/><category term='Maps'/><category term='VSTS'/><category term='DateTime'/><category term='Slowly Changing Dimension'/><category term='MCITP'/><category term='SSAS'/><category term='Sharepoint 2010'/><category term='PerformancePoint Server 2007'/><category term='Processing'/><category term='Ventas'/><category term='Data Cleansing'/><category term='SQL Server 2008 R2'/><category term='Data Warehouse'/><category term='Error'/><category term='T-SQL'/><category term='Null Value'/><category term='SSIS'/><category term='Cross-Time'/><category term='Timestamp'/><category term='Report Builder 3'/><category term='Time Dimension'/><category term='Andorra'/><category term='Barcelona'/><title type='text'>Microsoft Business Intelligence's Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://microsoft-business-intelligence.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-938253575614037930</id><published>2010-12-21T10:03:00.004+01:00</published><updated>2010-12-21T10:18:50.101+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='Sharepoint 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Integrar Sharepoint 2010 con Sql Server Integration Services</title><content type='html'>Últimamente me estoy encontrando muchos proyectos en los que tengo que conectarme a un portal Sharepoint 2010 para leer información e integrarla en un Data Warehouse. En Sharepoint 2007 existía un &lt;a href="http://sqlsrvintegrationsrv.codeplex.com/releases/view/17652"&gt;componente de Codeplex&lt;/a&gt; que hacía la integración realmente fácil, pero este componente ha dejado de funcionar si lo conectas a Sharepoint 2010. Espero que en algún momento alguien le eche un vistazo y arregle el error que da porque en principio los servicios Web de ambas plataformas continúan siendo iguales. Mientras tanto tendremos que programar la integración mediante el modelo de objetos de Sharepoint, lo cual implica:&lt;br /&gt;&lt;br /&gt;- Por un lado es un fastidio porque tendremos que programary definir las columnas manualmente. &lt;br /&gt;- Por otro lado, podremos personalizar y optimizar mejor la consulta a Sharepoint, controlar errores y hacer un logging más intenso que nos ayude en el desarrollo.&lt;br /&gt;&lt;br /&gt;Sin más, nos ponemos manos a la obra. Primero de todo deberemos insertar en el flujo de datos un componente de tipo "Script Component" que sea origen de datos. A continuación editamos el componente y definimos una a una las columnas que nos traeremos de Sharepoint en la pestaña "Input and Output":&lt;br /&gt;&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://ncsgdw.blu.livefilestore.com/y1p10vYIN_wOy91iKdSzZ0it6yYDaQwzyez5u2qXgDwY7ROBrSwSqFJkjx2zLWiFKR_sxj3EryrLpD6rdWLG4lknezJ4WAhEeYz/scriptSource.png"&gt;&lt;img src="http://ncsgdw.blu.livefilestore.com/y1prJ6iPsNGSdiQOFQRJA3ZjtrBZZatO7uTDqr3sltXle1pr6F8Ehd7l7QNxFYomNVde7Ad3bNGB4-e4P0Q3s2bbCQXYa5kGO-M/scriptSourceMini.png"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;A continuación editamos el código del script, pero antes de escribir nada deberemos añadir las 2 librerías necesarias para trabajar con el modelo de objetos de cliente de Sharepoint (Microsoft.SharePoint.Client.dll y Microsoft.SharePoint.Client.Runtime.dll). Éstas se encuentran en el directorio "%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ISAPI".&lt;br /&gt;&lt;br /&gt;Ahora ya podemos ir al método CreateNewOutputRows que el proxy genera por nosotros, y copiar el siguiente código:&lt;br /&gt;&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;using (ClientContext context = new ClientContext(Variables.iSiteURL))&lt;br /&gt;            {&lt;br /&gt;                context.Credentials = new NetworkCredential(Variables.vSPUsername, Variables.vSPPassword, Variables.vSPDomain);&lt;br /&gt;                List list = context.Web.Lists.GetByTitle(Variables.vMyListName);&lt;br /&gt;                CamlQuery camlQuery = new CamlQuery();&lt;br /&gt;                camlQuery.DatesInUtc = false;&lt;br /&gt;                camlQuery.ViewXml = "&lt;View/&gt;";&lt;br /&gt;                ListItemCollection listItems = list.GetItems(camlQuery);&lt;br /&gt;                context.Load(list);&lt;br /&gt;                context.Load(listItems);&lt;br /&gt;                context.ExecuteQuery();&lt;br /&gt;                foreach (ListItem listItem in listItems)&lt;br /&gt;                {&lt;br /&gt;                    Output0Buffer.AddRow();&lt;br /&gt;                    Output0Buffer.Id = listItem.Id;&lt;br /&gt;                    Output0Buffer.Title = (listItem["Title"] == null ? null : listItem["Title"].ToString());&lt;br /&gt;                    DateTime meetingDate;&lt;br /&gt;                    string myDateStr = (listItem["Data_x0020_convocat_x00f2_ria"] == null ? null : listItem["Data_x0020_convocat_x00f2_ria"].ToString());&lt;br /&gt;                    DateTime.TryParse(myDateStr, out myDate);&lt;br /&gt;                    if (myDate != DateTime.MinValue)&lt;br /&gt;                    {&lt;br /&gt;                        Output0Buffer.MyDateColumn = myDate;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Para evitar problemas con los credenciales, utilizo variables para guardar el usuario y password que utilizaré para la conexión. En caso contrario debería añadir la cuenta que ejecuta Visual Studio, SQL Server Integration Services o SQL Server Agent a Sharepoint para que el proceso pudiera conectar correctamente.&lt;br /&gt;&lt;br /&gt;A continuación declaro a qué lista tengo que contectar y la query CAML que utilizaré, la lista la guardo igualmente en una variable y la vista la mantengo al mínimo y en caso de querer optimizarla ya la tocaré. Si tengo fechas que leer y necesito que me las devuelva en hora local (no UTC) tengo que sobrescribir el parámetro DatesInUtc de la consulta. Finalmente ejecuto la consulta contra el servidor y proceso el resultado escribiendo una fila por cada elemento que la lista me devuelve. Como DateTime es un tipo de datos nativo, Sharepoint me devuelve MinValue cuando el campo en Sharepoint no tiene valor, así que es necesaria una conversión.&lt;br /&gt;&lt;br /&gt;Y eso es todo, al ejecutar este componente veremos como nuestro componente recupera las filas de Sharepoint y podemos tratarlas en nuestra pipeline de la manera que queramos.&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-938253575614037930?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/938253575614037930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/938253575614037930'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2010/12/integrar-sharepoint-2010-con-sql-server.html' title='Integrar Sharepoint 2010 con Sql Server Integration Services'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-4191359553169539885</id><published>2010-11-05T09:42:00.004+01:00</published><updated>2011-04-07T10:21:57.027+02:00</updated><title type='text'>Visio Services con Microsoft SharePoint 2010</title><content type='html'>Mucho tiempo sin publicar un post lo sé, y no soy de poner excusas así que por faena. Acabo de editar un video que quería colgar hace tiempo pues es bastante espectacular por su sencillez y su facilidad de uso. Se trata de un nuevo servicio de Microsoft Sharepoint 2010 llamado Visio Services. Con Visio Services podemos publicar cualquier diagrama de Visio en la Web de forma muy sencilla, incluso con formas de Visio asociadas a una fuente de datos.&lt;br /&gt;&lt;br /&gt;En este ejemplo voy a crear paso a paso un gráfico de un equipo de ventas con información de su estado de objetivos, desde cómo se crea el diagrama hasta su publicación en la home del departamento.&lt;br /&gt;&lt;br /&gt;Espero que os guste y veáis el potencial de esta opción.&lt;br /&gt;&lt;br /&gt;&lt;object width="640" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/BEtkrXQeBIA?fs=1&amp;amp;hl=es_ES"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/BEtkrXQeBIA?fs=1&amp;amp;hl=es_ES" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-4191359553169539885?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4191359553169539885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4191359553169539885'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2010/11/mucho-tiempo-sin-publicar-un-post-lo-se.html' title='Visio Services con Microsoft SharePoint 2010'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-6415477056459175837</id><published>2010-05-24T13:59:00.005+02:00</published><updated>2010-05-24T14:04:50.511+02:00</updated><title type='text'>Artículo publicado en Channel Partner</title><content type='html'>Hola de nuevo.&lt;br /&gt;&lt;br /&gt;Hace poco me pidieron que escribiera un artículo de opinión para una conocida web de expertos en distintos temas tecnológicos. El artículo trata sobre el futuro del Business Intelligence y las tendencias que marca el mercado. Lo podéis leer en el siguiente enlace:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.channelpartner.es/Voz/201005040018/El-business-intelligence-te-ayuda-a-analizar-primero-y-decidir-despues.aspx"&gt;http://www.channelpartner.es/Voz/201005040018/El-business-intelligence-te-ayuda-a-analizar-primero-y-decidir-despues.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Espero que sea de vuestro interés.&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-6415477056459175837?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/6415477056459175837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/6415477056459175837'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2010/05/articulo-publicado-en-channel-partner.html' title='Artículo publicado en Channel Partner'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-4408455775944378867</id><published>2010-03-26T18:14:00.010+01:00</published><updated>2010-03-26T18:27:20.058+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Analysis Services'/><category scheme='http://www.blogger.com/atom/ns#' term='SSAS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Mejores prácticas en Analysis Services (SSAS Best Practices)</title><content type='html'>Hola de nuevo.&lt;br /&gt;&lt;br /&gt;Hace poco tiempo estuve desarrollando una consultoría sobre una solución basada en Analysis Services para analizar cantidades bárbaras de información (del orden de miles de millones de filas en cada tabla). Como resultado de la consultoría hice un recopilatorio de buenas prácticas que toda solución completa de Analysis Services debería seguir. Os lo adjunto a continuación y espero que lo encontréis útil.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Diseño del Data Source View&lt;/h4&gt;&lt;br /&gt;• En el diseñador de cubos de Visual Studio, se recomienda en los DSVs separar en varios diagramas las tablas para una mayor claridad a la hora de diseñar. Una recomendación general es separar cada tabla de hechos con sus respectivas dimensiones relacionadas en un solo diagrama. Esto ayuda  también a diseñar siempre el cubo con un esquema OLAP en mente.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Diseño de las Dimensiones&lt;/h4&gt;&lt;br /&gt;• Establecer la propiedad HierarchyVisible a false para esconder los atributos que participan en las diferentes jerarquías de las dimensiones. De esta forma se obliga a los usuarios a navegar con las jerarquías y se evitan posibles errores en los resultados de los informes.&lt;br /&gt;• Asignar la propiedad AttributeHierarchyEnabled a false en aquellos atributos que no sean útiles para el análisis de información y permitir a los usuarios adquirir esta información mediante las propiedades del miembro o una acción de detalle, optimizando así el tiempo de procesado y el tamaño de los cubos.&lt;br /&gt;• Los atributos con una cardinalidad cercana a la clave de la dimensión para asignar la propiedad AttributeHierarchyOptimizedState a false, y así evitar la creación de índices innecesarios. En estos casos es recomendable además, si no existe ninguna jerarquía de negocio con ese atributo, habilitar una jerarquía adicional utilizando una agrupación ad-hoc (por ejemplo para el atributo nombre, crear una jerarquía Inicial-Nombre con la inicial del nombre) para facilitar la navegación del usuario.&lt;br /&gt;• Se recomienda además en las dimensiones con atributos con la misma cardinalidad que la clave primaria establecer la propiedad ProcessingGroup a ByTable para evitar consultas distinct en tiempo de procesado. &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Relaciones con las tablas de hechos&lt;/h4&gt;&lt;br /&gt;• Repasar el diseño para encontrar posibles relaciones many-to-many existentes que puedan ser convertidas a relación indirecta, para optimizar el tiempo de procesado y tiempos de respuesta de consultas.&lt;br /&gt;• Se recomienda también en el caso de tener claves foráneas nullables en el relacional utilizar una vista o una named query del DSV para enmascarar los Nulls y redirigirlos a un miembro desconocido “de negocio”, de forma que podamos diferenciar los hechos que se pierden por no tener informado este campo, y los errores de clave foránea que detecte la partición al procesar (2 miembros desconocidos, el nuestro y el de sistema).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Esquema de particionamiento de los grupos de medida:&lt;/h4&gt;&lt;br /&gt;• Se recomienda siempre particionar los grupos de medida. Las recomendaciones de Analysis Services sugieren particiones de entre 200Mb-3Gb con un máximo de 10-15 millones de filas, hasta un máximo de 2000 particiones.&lt;br /&gt;• Se recomienda particionar las tablas relacionales de la misma forma que se particionan cada uno de los grupos de medida del cubo, para optimizar los accesos a disco en el procesado en paralelo de particiones.&lt;br /&gt;• Se recomienda automatizar la creación y procesado de las particiones de las medidas, y asignar dinámicamente diseños distintos de agregaciones para particiones que varíen de uso con el tiempo (por ejemplo sobre la dimensión tiempo, asignar un esquema con más agregaciones a los últimos X meses mediante programación AMO).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Agregaciones&lt;/h4&gt;&lt;br /&gt;• Como ya se ha apuntado en el apartado anterior, se recomienda implementar más de un diseño de agregaciones para el conjunto de particiones de un grupo de medida que varíe con el uso a través del tiempo.&lt;br /&gt;• Una vez desplegado habilitar el log durante un tiempo suficiente con un trabajo intensivo de los usuarios de negocio y revisar los diseños de las agregaciones para optimizar aquellas agregaciones más críticas.&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-4408455775944378867?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4408455775944378867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4408455775944378867'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2010/03/mejores-practicas-en-analysis-services.html' title='Mejores prácticas en Analysis Services (SSAS Best Practices)'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-5576957049423166463</id><published>2010-03-25T09:37:00.005+01:00</published><updated>2010-03-25T09:44:45.352+01:00</updated><title type='text'>Videos de Sharepoint Insights 2010</title><content type='html'>Hola a todos.&lt;br /&gt;&lt;br /&gt;Últimamente en mi empresa, raona, hemos estado haciendo una serie de demos on-site con nuestros clientes de las nuevas características de análisis de información que traerán consigo los nuevos Microsoft Office 2010 y Microsoft Sharepoint Server 2010. He podido recopilar algunas de ellas en estos videos que ahora están disponibles vía Youtube. Os dejo el acceso directo a la playlist para que podáis verlos todos. Las demos son:&lt;br /&gt;&lt;br /&gt;• Demo de Office Excel 2010 con Powerpivot, para el análisis de datos en memoria.&lt;br /&gt;• Demo de Sharepoint Excel Services 2010, para publicación de contenido Excel en el portal.&lt;br /&gt;• Demo de Sharepoint la Chart Web Part, para visualizar datos rápidamente en Sharepoint.&lt;br /&gt;• Demo de PerformancePoint Services 2010, para el análisis avanzado y creación de cuadros de mando.&lt;br /&gt;&lt;br /&gt;Las tenéis todas en el siguiente link:&lt;br /&gt;&lt;br /&gt;&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/p/7434C43A0F840C73&amp;hl=en_US&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/p/7434C43A0F840C73&amp;hl=en_US&amp;fs=1" type="application/x-shockwave-flash" width="480" height="385" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-5576957049423166463?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5576957049423166463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5576957049423166463'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2010/03/videos-de-sharepoint-insights-2010.html' title='Videos de Sharepoint Insights 2010'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-7164562739418424945</id><published>2010-02-20T20:41:00.003+01:00</published><updated>2010-02-20T20:50:08.496+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Error'/><category scheme='http://www.blogger.com/atom/ns#' term='Processing'/><category scheme='http://www.blogger.com/atom/ns#' term='Analysis Services'/><category scheme='http://www.blogger.com/atom/ns#' term='SSAS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Error en SSAS: The attribute key cannot be found when processing...</title><content type='html'>Este error es el más común que te encontrarás si te dedicas a crear cubos OLAP con SQL Server Analysis Services. Para mí el modo en que este error se corrige dará credibilidad o no a los datos presentados por el cubo.&lt;br /&gt;&lt;br /&gt;Pero empezamos por el principio. Comienzas creando las dimensiones y grupos de medida del cubo, repasas las relaciones entre estas dimensiones y cada uno de estos grupos de medida, defines las jerarquías y relaciones entre atributos, incluso defines agregaciones y particiones para optimizar rendimiento y espacio en disco. En el momento en el que vas a procesar el cubo para ver los resultados el siguiente error se muestra:&lt;br /&gt;&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;The attribute key cannot be found when processing: Table: 'TableName', Column: 'ColumnName', Value: 'ErrorValue'. The attribute is 'AttributeName'.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;El error en el fondo es muy sencillo. En la tabla de hechos TableName tienes una clave foranea ColumnName que apunta a un registro de la dimensión cuyo atributo es AttributeName, y este registro, seguramente una clave subrogada, no se ha encontrado en la dimensión. Hablando en términos relacionales, se ha roto la integridad referencial pues la clave foranea apunta hacia un valor de clave primaria que no existe.&lt;br /&gt;&lt;br /&gt;En Analysis Services tenemos básicamente 4 modos de solventar esta situación:&lt;br /&gt;&lt;br /&gt;Opción 1) Modificamos el valor no encontrado con un valor correcto correspondiente a un miembro de la dimensión. Reprocesamos la dimensión y posteriormente volvemos a procesar el cubo.&lt;br /&gt;Opción 2) Modificamos la propiedad ErrorConfiguration del cubo o bien del grupo de medida, indicamos custom, y cambiamos la propiedad KeyErrorLimitAction a StopLogging y la propiedad KeyErrorAction a DiscardRecord. Finalmente procesamos el cubo.&lt;br /&gt;Opción 3) Modificamos la propiedad ErrorConfiguration del cubo o bien del grupo de medida, indicamos custom, y cambiamos la propiedad KeyErrorLimitAction a StopLogging, la propiedad KeyErrorAction a ConvertToUnknown y la propiedad UnknownMember de la dimensión a Visible. Reprocesamos la dimensión y posteriormente volvemos a procesar el cubo.&lt;br /&gt;Opción 4) Añadimos un miembro más a la dimensión llamado Unknown con una clave conocida (0 por ejemplo) y se la asignamos a este registro, de forma que se cumpla la integridad referencial. Reprocesamos la dimensión y posteriormente volvemos a procesar el cubo.&lt;br /&gt;&lt;br /&gt;Y ahora las implicaciones. La opción 1 nos puede servir cuando siempre exista un valor correcto y conocido para la dimensión, aunque esto no siempre es válido. En cualquier caso será la opción predilecta si podemos aplicarla. La segunda opción es un suicidio profesional en toda regla. El registro será ignorado por el cubo lo cual quiere decir que no se incluirá en el cálculo de las medidas. En definitiva, el resultado que lanzará el cubo no coincidirá con el resultado calculado en el relacional y el proyecto (y el autor del mismo) perderá toda la credibilidad. La opción 3 es una buena opción a la vez que rápida, el registro se incluirá en un miembro especial de la dimensión llamado miembro desconocido y los resultados calculados por el cubo serán correctos. El único problema puede ser que los usuarios vean raro un miembro fantasma que englobe todos los valores perdidos en el procesado, aunque es cuestión de acostumbrarlos. Finalmente una de mis opciones preferidas, crear un miembro desconocido propio que nos permita tener controlados los resultados que asignamos a este fantasma. De esta manera podemos tener claro qué valores se agregan en el miembro desconocido y solventar los valores que realmente son errores.&lt;br /&gt;&lt;br /&gt;En conclusión y por orden de preferencia utilizar la opción 1 siempre que se pueda, la opción 4 si tenemos valores desconocidos y queremos mantener el control total sobre los cálculos, la opción 3 si se quiere ir rápido (en fases de desarrollo y testing por ejemplo), y jamás la opción 2 a no ser que busquemos confundir al usuario o acabar nuestra carrera como ingenieros.&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-7164562739418424945?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/7164562739418424945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/7164562739418424945'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2010/02/error-en-ssas-attribute-key-cannot-be.html' title='Error en SSAS: The attribute key cannot be found when processing...'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-5581509721432378014</id><published>2010-01-31T19:38:00.005+01:00</published><updated>2010-01-31T19:47:11.881+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Cross-Time'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='Sales'/><category scheme='http://www.blogger.com/atom/ns#' term='Pipeline'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Ventas'/><title type='text'>¿Cómo crear una pipeline de ventas? (Cross-Time Sales Pipeline Howto)</title><content type='html'>Desde que me dedico a la inteligencia de negocio y en especial a la integración de datos, me han preguntado muchas veces cómo crear un informe de pipeline a partir de un histórico de oportunidades de venta, o lo que es lo mismo, un informe dónde se cuenta cuántas filas de una tabla existen en un determinado estado en unos instantes de tiempo marcados (Cross-time), por ejemplo cada mes.&lt;br /&gt;&lt;br /&gt;Después de buscar mucho y encontrar poco, la solución siempre ha sido crear una tabla de snapshots incrementales para cada instante del tiempo que contuviera la información básica con la que crear el informe. En ella utilizaría un procedimiento almacenado o bien un proceso SSIS para crear un bucle que me contase por ejemplo por cada mes y por cada estado, cuántas oportunidades de venta existían y guardar esta cifra en esta tabla.&lt;br /&gt;&lt;br /&gt;Hace poco he vuelto a encontrarme con esta necesidad, y en este caso un conjunto de filas reducido y un buen motor y esquema relacional me ha permitido implementar una solución sencilla y directa sin pasar por una tabla temporal. La idea es la misma, se necesita un proceso intermedio que esta vez implemento con una sencilla función escalar en T-SQL, pero puede servir de base a cualquiera que se encuentre con este problema alguna vez.&lt;br /&gt;&lt;br /&gt;La idea es utilizar la siguiente función en una consulta donde cruzamos la tabla de históricos con una tabla de dimensión de tiempo para recuperar los valores que buscamos para cada mes:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;CREATE FUNCTION [dbo].[fnFINGetPipelineAmount](@date as datetime, @state as varchar(20))&lt;br /&gt;  RETURNS numeric(38,20)&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;  DECLARE @total numeric(38,20);&lt;br /&gt;  SET @total = (select sum(New_EstRevenueQ) from&lt;br /&gt;(select rn=ROW_NUMBER() over (partition by ContractID, OpportunityId order by StartDate desc), *&lt;br /&gt;from Pipeline&lt;br /&gt;where ((month(@date) between month(StartDate) and MONTH(EndDate)) or (MONTH(StartDate) = month(@date) and EndDate is null))&lt;br /&gt;and YEAR(StartDate) = year(@date)&lt;br /&gt;AND (state = @state)&lt;br /&gt;) as sq where sq.rn = 1)&lt;br /&gt;  RETURN @total;&lt;br /&gt;END;&lt;br /&gt;&lt;/p&gt;&lt;/br&gt;&lt;br /&gt;Ahora sólo necesitamos la dimension tiempo para invocar a esta función y recuperar la pipeline completa para un lapso de tiempo determinado, por ejemplo el año pasado.&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;SELECT month, dbo.fnFINGetPipelineAmount(Date, 'New') AS NewAmount, dbo.fnFINGetPipelineAmount(Date, 'Proof') AS ProofAmount, dbo.fnFINGetPipelineAmount(Date, 'Close') AS CloseAmount&lt;br /&gt;FROM vwFIN_CubeDimTime&lt;br /&gt;where year = 2009 and IsLastDayOfMonth = 1&lt;br /&gt;&lt;/p&gt;&lt;/br&gt;&lt;br /&gt;Cuando el número de filas comienza a dispararse esta solución se vuelve demasiado costosa con facilidad. Para profundizar en este tema podemos leer una solución más compleja y efectiva en el whitepaper de Microsoft titulado "The many-to-many revolution" pág 57., de Marco Russo, el cual recomiendo a aquellos que les guste el mundo OLAP. Lo podéis encontrar &lt;a class="link" href="http://www.sqlbi.eu/manytomany.aspx"&gt;aquí&lt;/a&gt;.&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-5581509721432378014?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5581509721432378014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5581509721432378014'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2010/01/como-crear-una-pipeline-de-ventas-cross.html' title='¿Cómo crear una pipeline de ventas? (Cross-Time Sales Pipeline Howto)'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-5849065401505311559</id><published>2009-12-14T13:08:00.003+01:00</published><updated>2009-12-14T13:13:06.186+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Report Builder 3'/><category scheme='http://www.blogger.com/atom/ns#' term='Maps'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Mapa con Report Builder 3.0 Maps y SQL Server 2008</title><content type='html'>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!!!&lt;/br&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/iM3uiS-BsQ4&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/iM3uiS-BsQ4&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-5849065401505311559?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5849065401505311559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5849065401505311559'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2009/12/mapa-con-report-builder-30-maps-y-sql.html' title='Mapa con Report Builder 3.0 Maps y SQL Server 2008'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-6385357061733247201</id><published>2009-12-09T15:56:00.003+01:00</published><updated>2009-12-09T15:58:19.756+01:00</updated><title type='text'>Artículo publicado en MSDN</title><content type='html'>Hola a todos.&lt;br /&gt;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:&lt;/br&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/es-es/ee815809.aspx"&gt;http://msdn.microsoft.com/es-es/ee815809.aspx&lt;/a&gt;&lt;/br&gt;&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-6385357061733247201?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/6385357061733247201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/6385357061733247201'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2009/12/articulo-publicado-en-msdn.html' title='Artículo publicado en MSDN'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-8230871017178868594</id><published>2009-12-04T17:01:00.002+01:00</published><updated>2009-12-04T17:10:33.082+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Report Builder 3'/><category scheme='http://www.blogger.com/atom/ns#' term='Powerpivot'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008 R2'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Office Excel'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>SQL Server 2008 R2</title><content type='html'>Hola a todos.&lt;br /&gt;Hace unos días se liberó la CTP de Noviembre de SQL Server 2008 R2. Podéis acceder directamente mediante este link:&lt;br /&gt;&lt;a href="http://www.microsoft.com/sqlserver/2008/en/us/R2Downloads.aspx"&gt;http://www.microsoft.com/sqlserver/2008/en/us/R2Downloads.aspx&lt;/a&gt;&lt;br /&gt;Adicionalmente podéis descargar el complemento Report Builder 3 con nuevas y espectaculares funcionalidades. El acceso directo a la descarga es:&lt;br /&gt;&lt;a href="http://download.microsoft.com/download/5/4/D/54D3A5E3-71EF-45B7-BA9D-02F0A7C4ABB7/ReportBuilder3.msi"&gt;http://download.microsoft.com/download/5/4/D/54D3A5E3-71EF-45B7-BA9D-02F0A7C4ABB7/ReportBuilder3.msi&lt;/a&gt;&lt;br /&gt;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.&lt;br /&gt;Puedes descargar la beta 2 de Office Excel en el mismo link que la CTP de SQL Server 2008 R2.&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-8230871017178868594?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/8230871017178868594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/8230871017178868594'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2009/12/sql-server-2008-r2.html' title='SQL Server 2008 R2'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-5719005607322223872</id><published>2009-10-28T16:54:00.004+01:00</published><updated>2009-12-04T16:56:37.849+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Deployment'/><category scheme='http://www.blogger.com/atom/ns#' term='Configuration'/><category scheme='http://www.blogger.com/atom/ns#' term='Connection String'/><title type='text'>Herramienta de deploy personalizada con SSIS</title><content type='html'>Hola a todos. &lt;br /&gt;Demasiado tiempo sin publicar, supongo. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;Puedes descargar el proyecto completo y la herramienta desde &lt;a href="http://lgtpia.blu.livefilestore.com/y1pe649v_xIdMogC0Yfj8hSseRKV5YEPU5t6zghxgwVfgW7zTXBt_jKoP_J9tK06k1FVrpN3YgfSYkx3tawVUmT_Q/ConfigFileSet.rar?download"&gt;aquí&lt;/a&gt;.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-5719005607322223872?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5719005607322223872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/5719005607322223872'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2009/10/ssis-custom-deployment-utility-with.html' title='Herramienta de deploy personalizada con SSIS'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-1965104041490734473</id><published>2009-04-27T17:26:00.007+02:00</published><updated>2009-12-04T16:56:48.648+01:00</updated><title type='text'>Limpieza de datos (Data Cleansing) con Script en SSIS</title><content type='html'>Hola chicos. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;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:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;Imports System&lt;br /&gt;Imports System.Data&lt;br /&gt;Imports System.Math&lt;br /&gt;Imports System.Reflection&lt;br /&gt;Imports Microsoft.SqlServer.Dts.Pipeline&lt;br /&gt;Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper&lt;br /&gt;Imports Microsoft.SqlServer.Dts.Runtime.Wrapper&lt;br /&gt;&lt;br /&gt;Public Class ScriptMain&lt;br /&gt;    Inherits UserComponent&lt;br /&gt;&lt;br /&gt;    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)&lt;br /&gt;        Dim str As String&lt;br /&gt;        Dim obj As Object&lt;br /&gt;        Try&lt;br /&gt;            Dim p As PropertyInfo&lt;br /&gt;            For Each p In Row.GetType().GetProperties()&lt;br /&gt;                'First check, null properties&lt;br /&gt;                If p Is Nothing Then&lt;br /&gt;                    Continue For&lt;br /&gt;                End If&lt;br /&gt;                'Second check, null values&lt;br /&gt;                If p.GetValue(Row, Nothing) Is Nothing Then&lt;br /&gt;                    Continue For&lt;br /&gt;                End If&lt;br /&gt;                'Second check by types&lt;br /&gt;                If p.PropertyType Is GetType(String) Then&lt;br /&gt;                    p.SetValue(Row, CleanString(p.GetValue(Row, Nothing).ToString()), Nothing)&lt;br /&gt;                End If&lt;br /&gt;                If p.PropertyType Is GetType(DateTime) Then&lt;br /&gt;                    If CType(Row.GetType().GetProperty(p.Name() + "_IsNull").GetValue(Row, Nothing), Boolean) = True Then&lt;br /&gt;                        Continue For&lt;br /&gt;                    End If&lt;br /&gt;                    obj = CleanDate(p.GetValue(Row, Nothing))&lt;br /&gt;                    If obj Is Nothing Then&lt;br /&gt;                        Row.GetType().GetProperty(p.Name() + "_IsNull").SetValue(Row, True, Nothing)&lt;br /&gt;                    Else&lt;br /&gt;                        p.SetValue(Row, obj, Nothing)&lt;br /&gt;                    End If&lt;br /&gt;                End If&lt;br /&gt;            Next&lt;br /&gt;        Catch e As Exception&lt;br /&gt;            'Do Nothing&lt;br /&gt;        End Try&lt;br /&gt;    End Sub&lt;br /&gt;&lt;br /&gt;    Public Function CleanString(ByVal str As String) As String&lt;br /&gt;        If str.Trim() = "" Then&lt;br /&gt;            Return Nothing&lt;br /&gt;        End If&lt;br /&gt;        Return str&lt;br /&gt;    End Function&lt;br /&gt;&lt;br /&gt;    Public Function CleanDate(ByVal obj As Object) As Object&lt;br /&gt;        Dim dt As DateTime&lt;br /&gt;        dt = CType(obj, DateTime)&lt;br /&gt;        If dt &gt; DateTime.Now Then&lt;br /&gt;            Return Nothing&lt;br /&gt;        End If&lt;br /&gt;        Return obj&lt;br /&gt;    End Function&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;/p&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-1965104041490734473?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/1965104041490734473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/1965104041490734473'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2009/04/custom-data-cleansing-with-ssis.html' title='Limpieza de datos (Data Cleansing) con Script en SSIS'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-4386875123500117940</id><published>2009-03-22T02:36:00.010+01:00</published><updated>2009-12-04T16:56:54.786+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='Timestamp'/><title type='text'>Extracción de datos con marca de tiempo (Timestamp Data Extraction) con SSIS</title><content type='html'>Hola a todos. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;Vamos a ver cómo hacerlo con un ejemplo. &lt;br /&gt;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: &lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1p07lQ_K2TJWMivvT6m8Gsy4r6Wkqp9U29FXSarannRoRtfTV-XqTUnOzUoj2o59BOsCR29bbnmeFRuHGLgsKOpwXJrVaEGQy7/Timestamp01.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1p07lQ_K2TJWMivvT6m8Gsy4r6Wkqp9U29FXSarannRoRtfTV-XqTUnOzUoj2o59BOsCR29bbnmeFRuHGLgsKOpwXJrVaEGQy7/Timestamp01.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;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: &lt;br /&gt;• 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.&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;SELECT LastReadTimestamp FROM LastReadTimestamps WHERE TableName = 'customers'&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;• 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. &lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;SELECT convert(varchar(20),convert(numeric(20,0),max(timestamp) + 0)) AS timestamp FROM dbo.Customers&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;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: &lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;SELECT CustomerID,Name,Surname,Location &lt;br /&gt;FROM Customers &lt;br /&gt;WHERE convert(numeric(20,0),timestamp + 0) &gt; ? AND convert(numeric(20,0),timestamp + 0) &lt;= ?&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;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: &lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1pRXsVo1UKkoNDRrs7mAqtTpOk0azR1qyPX13F-uF1fGrMHMpVe65p-gH13XN2GMi2THieFSb_fdp3xW1oiJo60jeJEzjdQfgi/Timestamp03.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1pRXsVo1UKkoNDRrs7mAqtTpOk0azR1qyPX13F-uF1fGrMHMpVe65p-gH13XN2GMi2THieFSb_fdp3xW1oiJo60jeJEzjdQfgi/Timestamp03.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;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:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;UPDATE LastReadTimestamps&lt;br /&gt;SET LastReadTimestamp = convert(numeric(20,0), ?)&lt;br /&gt;WHERE TableName = 'Customers'&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1pX1rjl2ibTtMwGzyAZsCbuJcqowaQ1y2UJTBnccSFYPD3DMoAIaG5XdiHqDqQFnzsSkY1lbVdRkgp1SYmfLCmWzsgS-IQA8o4/Timestamp02.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1pX1rjl2ibTtMwGzyAZsCbuJcqowaQ1y2UJTBnccSFYPD3DMoAIaG5XdiHqDqQFnzsSkY1lbVdRkgp1SYmfLCmWzsgS-IQA8o4/Timestamp02.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;Espero que hayan encontrado interesante este artículo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-4386875123500117940?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4386875123500117940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4386875123500117940'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2009/03/timestamp-data-extraction-with-ssis.html' title='Extracción de datos con marca de tiempo (Timestamp Data Extraction) con SSIS'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-4026590786949668651</id><published>2008-12-04T16:33:00.007+01:00</published><updated>2009-12-04T16:57:02.129+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Time Dimension'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Crear una dimensión de tiempo (Time Dimension)</title><content type='html'>Hola a todos. &lt;br /&gt;&lt;br /&gt;Recientemente me he visto en la necesidad de crear una dimensión de tiempo en un nuevo Data Warehouse en una empresa financiera, por lo que tuve que utilizar un script de SQL Server para crear la tabla y rellenarla. Os lo dejo por si os véis en mi misma situación, que tengáis como mínimo por dónde empezar: &lt;br /&gt;&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;CREATE TABLE TIME (&lt;br /&gt; TIME_KEY smalldatetime,&lt;br /&gt; [DAY] int,&lt;br /&gt; [MONTH] int,&lt;br /&gt; [QUARTER] int,&lt;br /&gt; [SEMESTER] int,&lt;br /&gt; [HALF] int,&lt;br /&gt; [YEAR] int,&lt;br /&gt; [WEEKDAY] int,&lt;br /&gt; [WEEK_OF_YEAR] int,&lt;br /&gt; [MONTH_NAME] varchar(20),&lt;br /&gt; [QUARTER_NAME] varchar(2),&lt;br /&gt; [SEMESTER_NAME] varchar(2),&lt;br /&gt; [HALF_NAME] varchar(2),&lt;br /&gt; [WEEKDAY_NAME] varchar(10),&lt;br /&gt; [DATE] [smalldatetime],&lt;br /&gt; PRIMARY KEY CLUSTERED (TIME_KEY)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;SET DATEFORMAT dmy&lt;br /&gt;&lt;br /&gt;DECLARE @startDate SMALLDATETIME&lt;br /&gt;DECLARE @currentDate AS SMALLDATETIME&lt;br /&gt;DECLARE @maxDate AS DATETIME&lt;br /&gt;DECLARE @halfNbr AS INT&lt;br /&gt;DECLARE @semesterNbr AS INT&lt;br /&gt;DECLARE @monthName AS VARCHAR(50)&lt;br /&gt;DECLARE @quarterName AS VARCHAR(2)&lt;br /&gt;DECLARE @semesterName AS VARCHAR(2)&lt;br /&gt;DECLARE @halfName AS VARCHAR(2)&lt;br /&gt;DECLARE @weekDayName AS VARCHAR(10)&lt;br /&gt;&lt;br /&gt;SET @startDate = '20040101'&lt;br /&gt;SET @maxDate = DATEADD(YEAR, 25, GETDATE())&lt;br /&gt;SET @currentDate = @startDate&lt;br /&gt; &lt;br /&gt;WHILE (@currentDate &lt; @maxDate)&lt;br /&gt;BEGIN&lt;br /&gt;   SET @semesterNbr = CASE WHEN MONTH(@currentDate) &lt; 5 THEN 1 WHEN MONTH(@currentDate) &gt; 8 THEN 3 ELSE 2 END&lt;br /&gt;   SET @halfNbr = CASE WHEN MONTH(@currentDate) &lt; 7 THEN 1 ELSE 2 END&lt;br /&gt;      SET @monthName = DATENAME(MONTH, @currentDate)&lt;br /&gt;      SET @quarterName =  'Q' + CONVERT(char(1), DATEPART(QUARTER, @currentDate))&lt;br /&gt;      SET @semesterName =  'S' + CONVERT(char(1), @semesterNbr)&lt;br /&gt;      SET @halfName =  'H' + CONVERT(char(1), @halfNbr)&lt;br /&gt;   SET @weekDayName = DATENAME(WEEKDAY, @currentDate)&lt;br /&gt; &lt;br /&gt;      INSERT INTO [TIME]&lt;br /&gt;            VALUES(@currentDate, DAY(@currentDate), MONTH(@currentDate), DATEPART(QUARTER,@currentDate), &lt;br /&gt;   @semesterNbr, @halfNbr, YEAR(@currentDate), DATEPART(WEEKDAY, @currentDate), &lt;br /&gt;   DATEPART(WEEK,@currentDate), @monthName, @quarterName, @semesterName, @halfName, &lt;br /&gt;   DATENAME(WEEKDAY, @currentDate), @currentDate)&lt;br /&gt;      SET @currentDate = DATEADD(DAY, 1, @currentDate)&lt;br /&gt;END&lt;br /&gt;&lt;/p&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-4026590786949668651?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4026590786949668651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/4026590786949668651'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/12/create-custom-time-dimension.html' title='Crear una dimensión de tiempo (Time Dimension)'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-437467235296795721</id><published>2008-11-11T21:16:00.009+01:00</published><updated>2009-12-04T16:57:10.706+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Slowly Changing Dimension'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='SCD'/><title type='text'>Optimización del procesamiento de dimensiones (SCD o Slowly Changing Dimension) en SSIS</title><content type='html'>En un almacén de datos, es muy común tener  que tratar con más de una dimensión, a menudo originadas desde varias fuentes de datos, y posiblemente todas ellas cambiando constantemente en el tiempo. Las necesidades del negocio hacen que muchas veces se quieran guardar todos los cambios que ha habido para consultas históricas.&lt;br /&gt;Todas estas dimensiones cambiantes (SCDs) pueden complicar el proceso ETL, especialmente para las de tipo histórico (SCD tipo 2) donde se debe mantener un registro histórico de los datos cambiantes. En SSIS por suerte, tenemos un componente para procesar este tipo de dimensiones, incluido en las tareas del flujo de datos: el componente Slowly Changing Dimension Component (componente SCD en adelante).&lt;br /&gt;Sin embargo, uno de los principales problemas que este componente presenta ha sido siempre su rendimiento. Para entender este problema vamos a echar un vistazo a su comportamiento:&lt;br /&gt;Para cada fila de la pipeline de entrada, el componente lanza una consulta SQL para recuperar la fila existente en destino y buscar valores que cambien respecto de los que vienen en la pipeline. Si existe algún valor señalado como no-histórico, el componente simplemente actualizará la fila en destino con los nuevos valores. Si existe algún valor que cambie del tipo histórico, entonces se realiza una actualización del registro de destino existente y se marca como no válido, para después realizar una inserción de una nueva fila con la nueva versión de la fila.&lt;br /&gt;Estamos hablando de una consulta de selección, de una consulta de actualización y de una inserción (ésta sólo para las filas con cambios históricos) para cada una de las filas de destino.&lt;br /&gt;En este artículo describiré las diferentes aproximaciones que podemos tomar para optimizar el rendimiento de nuestros paquetes con procesamiento de dimensiones y así, optimizar la carga de nuestro almacén de datos.&lt;br /&gt;&lt;br /&gt;Para ilustrar el ejemplo utilizaré las siguientes bases de datos:&lt;br /&gt;• Una base de datos origen ‘SourceDB’, con una tabla ‘Product’.&lt;br /&gt;• Una base de datos destino ‘DataWarehouseDB’, con una tabla ‘DimProduct’&lt;br /&gt;&lt;br /&gt;&lt;p class="mih2"&gt;Type 1 Slowly Changing Dimensions (no históricas)&lt;/p&gt;&lt;br /&gt;Cuando trabajamos con dimensiones cambiantes de tipo 1, lo único que debemos hacer es actualizar las filas en las que detectemos algún cambio, sin necesidad de mantener ninguna información histórica. Si detectamos el cambio, la fila se actualizará y perderemos el valor que existía antes.&lt;br /&gt;&lt;p class="mih3"&gt;Usando el componente SCD de SSIS&lt;/p&gt;&lt;br /&gt;Podemos construir un flujo de datos que implemente el escenario que hemos descrito con un componente SCD de SSIS. Podemos verlo en la figura 1:&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1pMdqbb_k8PDkuox8H3XLHlcOh2ycgYJH_NSh7XYXl1OQ3EJacMHxZtTf21VD-tQEjNiKMtcKbF0TmGOVezQBsLHHXzTx7q2PG/SCDimg1.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1p_RhuTq2ux5V0DaEi34kjq6In3V75N9b1kzq_vTaHVWtcmLfJZhHcUsj8cPMFSvXh3akCAfH42OJAvbRZOLRPdWXcii_6e-HF/SCDimg1Mini.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;Para cada fila que recupere el componente OLEDB que lee de la tabla ‘Products’ de la base de datos origen, el componente SCD ejecutará una consulta SQL contra la tabla ‘DimProduct’ para ver si ese producto ya existe. En el caso de que no exista redirigirá la fila hacia la salida ‘New Output’ y acabará con una inserción mediante el componente OLEDB de destino .En el caso de que exista, comprobará si la fila leída contiene valores diferentes a los de la fila en la pipeline. Si hay cambios redirigirá la fila hacia el componente comando OLEDB que actualizará la fila en destino con los nuevos valores.&lt;br /&gt;Dado el comportamiento del componente podemos esperar un rendimiento pobre. A continuación veremos cómo podemos optimizar este flujo de datos sin excesiva complejidad añadida.&lt;br /&gt;&lt;br /&gt;&lt;p class="mih3"&gt;La solución con dimensiones cambiantes de tipo 1&lt;/p&gt;&lt;br /&gt;Afortunadamente, podemos aumentar considerablemente el rendimiento de nuestra pipeline en el flujo de datos, sustituyendo el componente SCD por un componente de Lookup más otro de tipo Split.&lt;br /&gt;Para conseguir esta optimización, borraremos el componente SCD del flujo de datos, dejando los componentes OLEDB generados debajo por el propio SCD. A continuación añadiremos un componente de Lookup para recuperar las filas de DimProduct, tal y como lo haría el componente SCD, es decir, recuperando únicamente las columnas de los valores cambiantes y las que compongan la clave de negocio.&lt;br /&gt;Después añadiremos un componente de tipo Conditional Split. En este componente añadiremos una condición llamada ‘Actualizar’ con todas las comparaciones necesarias entre los valores cambiantes.&lt;br /&gt;El nuevo flujo de datos debería quedar como el siguiente diagrama:&lt;br /&gt;&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1psRK37fUdKS5G1XqpDVh7rY8Cv6m0D3j1f6JsCzMBk3vLat96aE1qFfnugBxB3UAaWkNOkTEjytM2tyenUhNFSkuZ1PuNaC4x/SCDimg2.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1ppr-6pRZ7PmYJ1UFJRtrv1bapee-KNupOCf0Iw_IPCzJc6t3W5OCK7efK7sxDldyJSubhq2RRJn6JtiPYvMJTQ2nqzvKzUJ5o/SCDimg2Mini.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;Hay que tener en cuenta que no se puede utilizar una única comparación entre los valores cambiantes para averiguar si ha cambiado, ya que nos pueden llegar valores nulos. Por ejemplo, si queremos hacer la comparación entre el campo ‘ProductCategory’ fuente y destino, la expresión que usaremos será la siguiente:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;!((ISNULL(SRCPRODUCTCATEGORY) &amp;&amp; ISNULL(DWDIMPRODUCTCATEGORY)) || (!ISNULL(SRCPRODUCTCATEGORY) &amp;&amp; !ISNULL(DWDIMPRODUCTCATEGORY) &amp;&amp; (SRCPRODUCTCATEGORY == DWDIMPRODUCTCATEGORY)))&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;Con esta expresión evitaremos que los valores nulos provoquen cambios no deseados, y sólo actualizaremos si el cambio se produce por dos valores diferentes. Podemos repetir esta comparación en la expresión de condición del componente Split. &lt;br /&gt;Lo único que queda es conectar la salida de error del componente Lookup al componente OLEDB de inserción, y la salida de ‘Actualizar’ al componente OLEDB de actualización.&lt;br /&gt;El resultado final en nuestro ejemplo es que el componente Lookup recuperará en una sola operación las filas de destino y las mantendrá en memoria durante la ejecución del flujo de datos. Después de comparar cada fila con el Dataset que mantiene en memoria, realizará de la misma forma la inserción o la actualización en función de si se encuentra la fila en destino o no. La diferencia radica en el número de transacciones, que se reduce enormemente ya que no es necesario recuperar fila por fila para hacer la comparación.&lt;br /&gt;&lt;p class="mih2"&gt;Type 2 SCD (Históricas)&lt;/p&gt;&lt;br /&gt;This was the SCD 1 type optimization, but we should use the SCD 2 type every time that a dimension has an historical attribute. If an historical attribute has been changed then rather than just u0pdate the destination row with the new values, the OLEDB component must mark the existing row as out-of-date, and then insert a new row with the new values. For example, if we want to track all the pricing changes in time, we'll have to insert a new row every time that we detect that the prize has been changed in the source system.&lt;br /&gt;&lt;p class="mih3"&gt;Type 2 SCD with the SCD Component&lt;/p&gt;&lt;br /&gt;En el caso de que queramos implementar algún campo histórico, deberemos utilizar la aproximación de las dimensiones cambiantes de tipo 2 (SCD 2). En este caso, si un atributo histórico ha cambiado entonces en lugar de tan sólo actualizar la fila de destino con el valor nuevo, el componente deberá marcar la fila actual como inválida, e insertar una nueva fila con los nuevos valores. Por ejemplo si queremos registrar todos los cambios de precio de un producto, deberemos insertar una nueva fila cada vez que detectemos que un producto ha cambiado su precio en la fuente de datos.&lt;br /&gt;Podemos diseñar un flujo de datos con este comportamiento de forma muy sencilla gracias al componente SCD de SSIS. Si seleccionamos el atributo precio como un atributo histórico en el asistente del componente SCD, el flujo de datos resultante debería parecerse al siguiente:&lt;br /&gt;&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1pWGpNAF7cPoVcbr2aJMhvX1tYxi4xaNTTk3As7-u1qR6zWF3iqLj3LTIPo2g-JFnn0GZT0sE-tB7vPK2Kox7Xb-RQnVmhmKuP/SCDimg3.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1p7GkzKxr-xWAuH_K1HKLvAI4G6pE9C87c7FaXG3mm8XXEEL6D11YpfUzg8lrRS4wHxQT407sUSE-6o35Eh3eXihPnF0mPO-3v/SCDimg3Mini.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;&lt;br /&gt;&lt;p class="mih3"&gt;La solución con dimensiones cambiantes de tipo 2&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Los pasos para optimizar este componente en este caso son muy similares al proceso que hemos seguido en el caso del SCD de tipo 1. Deberemos borrar el componente SCD una vez completado el asistente, y añadir un componente Lookup que devuelva los registros de la tabla DimProduct y un componente de Split. El componente de Lookup deberá recuperar tanto los atributos cambiantes como los históricos.&lt;br /&gt;Para controlar los dos tipos de cambio utilizaremos el component Split. Tendremos una condición para los campos históricos y otra para los campos cambiantes. El comportamiento esperado será que si existe un campo histórico que ha cambiado no será necesario continuar mirando si existe algún cambio de tipo 1 ya que irá igualmente a la rama del histórico. Para conseguir este comportamiento lo único que tenemos que hacer es colocar la condición del histórico en primer lugar, ya que el componente procesa las condiciones en orden. En la siguiente figura podemos ver cómo queda configurado el componente Split:&lt;br /&gt;&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1pV1B702BHXcGYFgKQf-efLt36pvqCCLNVtfApjXJjDAck5NwpfwTcxr6Kq7mrqtsWHwF8CTj7aiaWPPJywqbrrJlzeObi0wV2/SCDimg4.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1p3rl_Q39suGkbOVBl7LBU9O3vS7yPptGJs5jAsx14oROOs1EOit88VBvMJxfaam26G43CN1__YZs_c2wio__5l0Ra21GelmgY/SCDimg4Mini.png"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;br /&gt;Como último paso, conectaremos las salidas convenientes a los componentes que había generado el SCD de SSIS, y el flujo de datos quedará listo. El nuevo flujo deberá tener un aspecto similar a este:&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1p3rl_Q39suGl4SVgc6Ii0orswigygu8bW3IVt9dpAixHwaqYLQOLmKG6aiFIuE_0BedBhDTwEwE_vNtkv6EB0zazImvOhmRrD/SCDimg5.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1pFgn6pJHZF5yF3S5yBGworhR7Y8wTZFn7tR-eEIu8I_u3OmFMcPL2-S81o3i_UVPp5vRKpGgUjeD-4jujwiOWOQtjsV0vlXBq/SCDimg5Mini.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;&lt;p class="mih3"&gt;Comparación del rendimiento&lt;/p&gt;&lt;br /&gt;Para comparar el rendimiento de los 2 flujos, vamos a ejecutar el paquete sobre la tabla Product de la base de datos AdventureWorks. &lt;br /&gt;En la carga de datos, se obtienen los siguientes tiempos de ejecución:&lt;br /&gt;Primera carga:&lt;br /&gt;- Con componente SCD de SSIS: 73 segundos&lt;br /&gt;- Con Lookup+Split: 65 segundos&lt;br /&gt;Debemos tener en cuenta que los tiempos de validación del paquete son idénticos para ambos flujos, de ahí la escasa diferencia entre ambas ejecuciones.&lt;br /&gt;Ahora cambiaremos algunos atributos en la categoría y precio de algunos productos de la tabla Product. El siguiente script se encargará de ello:&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1p11l8b1ayi3UcT7SPDF5zobqdjh6bHHpvm9mdGCLPdedm2y6ZGDhreEYjtIq2V90gvR1ttia6-wRQ40sbpD0mWVPEZeI35GLj/SCDimg6.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1p11l8b1ayi3UcT7SPDF5zobqdjh6bHHpvm9mdGCLPdedm2y6ZGDhreEYjtIq2V90gvR1ttia6-wRQ40sbpD0mWVPEZeI35GLj/SCDimg6.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;Los tiempos del proceso de actualización son:&lt;br /&gt;- Con componente SCD de SSIS: 74 seconds&lt;br /&gt;- Con Lookup+Split: 65 seconds&lt;br /&gt;Los resultados no son tan apasionantes como esperábamos, pero debemos tener en cuenta que una dimensión de 500 filas está muy lejos de ser apasionante. Simularemos una dimensión de 100.000 filas cambiando la sentencia SQL de origen por la siguiente:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;SELECT PRODUCTID, NAME,  '1'+ PRODUCTNUMBER AS PRODUCTNUMBER, LISTPRICE, PRODUCTSUBCATEGORYID, MODIFIEDDATE FROM PRODUCTION.PRODUCT UNION ALL &lt;br /&gt;SELECT PRODUCTID, NAME,  '2'+ PRODUCTNUMBER AS PRODUCTNUMBER, LISTPRICE, PRODUCTSUBCATEGORYID, MODIFIEDDATE FROM PRODUCTION.PRODUCT UNION ALL &lt;br /&gt;[...]&lt;br /&gt;SELECT PRODUCTID, NAME,  '200'+ PRODUCTNUMBER AS PRODUCTNUMBER, LISTPRICE, PRODUCTSUBCATEGORYID, MODIFIEDDATE FROM PRODUCTION.PRODUCT &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;Después de truncar la tabla DimProduct y repetir los tests de nuevo. Los resultados los podemos ver a continuación:&lt;br /&gt;Primera carga:&lt;br /&gt;- Con componente de SCD de SSIS: 11 minutos 8 segundos&lt;br /&gt;- Con Lookup+Split: 2 minutos 10 segundos&lt;br /&gt;Proceso de actualización:&lt;br /&gt;- Con componente de SCD de SSIS: 178 minutos 05 segundos&lt;br /&gt;- Con Lookup+Split: 121 minutos 23 minutos&lt;br /&gt;Los resultados son mucho más significantes, y ahora sí que podemos ver la enorme diferencia entre un diseño y otro. Debemos tener en cuenta además que si tuviéramos realmente una dimensión de 100.000 filas el servidor debería mover muchas más páginas de disco y los resultados seguramente serían más significativos todavía.&lt;br /&gt;Hay que fijarse en la diferencia abismal entre la primera carga y la actualización posterior. Esto es debido básicamente a la diferencia de coste que tienen ambas instrucciones para el servidor SQL Server. Realizar una actualización requiere localizar la página de disco donde se encuentra ubicada la fila, modificar su valor y escribir de nuevo la página. &lt;br /&gt;Con esta premisa sería posible crear una optimización adicional, consistente en modificar el componente OLEDB de actualización y combinar un componente OLEDB de inserción en una tabla temporal con una instrucción JOINED UPDATE en otro componente OLEDB de actualización. Como ejercicio individual, os dejo que probéis los beneficios de esta aproximación.&lt;br /&gt;&lt;br /&gt;&lt;p class="mih2"&gt;Conclusión&lt;/p&gt;&lt;br /&gt;Podemos conseguir una importante mejora del rendimiento en paquetes de procesamiento de dimensiones si implementamos estas optimizaciones en nuestros flujos de datos. El componente SCD de SSIS realmente supone una sobrecarga de trabajo para el proceso que puede ser mejorada de forma sencilla y rápida.&lt;br /&gt;Por el contrario es justo destacar que esta mejora conlleva un aumento de la complejidad del paquete, y por tanto perjudica su desarrollo y mantenimiento.&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-437467235296795721?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/437467235296795721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/437467235296795721'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/11/scd-slowly-changing-dimension.html' title='Optimización del procesamiento de dimensiones (SCD o Slowly Changing Dimension) en SSIS'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-3616121471548125555</id><published>2008-10-27T15:18:00.006+01:00</published><updated>2009-12-04T16:57:19.240+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='Barcelona'/><category scheme='http://www.blogger.com/atom/ns#' term='Seminar'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='Andorra'/><title type='text'>Varios seminarios de Business Intelligence</title><content type='html'>Hola a todos. &lt;br /&gt;&lt;br /&gt;El mes pasado, estuve realmente ocupado preparando dos seminarios de Business Intelligence para ampliar la competencia de BI dentro de la empresa donde trabajo. Estos seminarios tuvieron lugar en Barcelona y en Andorra la Vella. &lt;br /&gt;&lt;p class="link"&gt;&lt;a href="http://lgtpia.blu.livefilestore.com/y1p0lS1pXn0uaYy_3XbcKS_5SlFbVXdm01KF5YI5IaFEmFHDX6LaMpdwiotoXgZjNzQocePjxLiNcXf24pUKTxO3tlm82x8MAla/semAndorra.jpg"&gt;&lt;img style="border: none" src="http://lgtpia.blu.livefilestore.com/y1pIEb-JpQsznTc1KvEHj-ebki2sKlKYN0lzSLtcbXvlfF35_-sjoUMAlCvi0gCpWxqWvzNDWvv4FpTFPpWXLHyuGVOgQafK00B/semAndorraMini.jpg"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;En Barcelona estuve hablando alrededor de tres horas acerca de las mejoras de SQL Server 2008 y el Case Study de GMAC RFC, la división financiera perteneciente a General Motors dedicada a hipotecas en España. En Andorra sin embargo, sólo tuve 45 minutos, así que acabé hablando de la situación actual del mundillo del BI en el mercado y algunos case studies representativos.&lt;br /&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-3616121471548125555?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/3616121471548125555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/3616121471548125555'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/10/business-intelligence-seminars.html' title='Varios seminarios de Business Intelligence'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-298683739842626087</id><published>2008-09-15T15:53:00.007+02:00</published><updated>2009-12-04T16:57:25.353+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Logging personalizado (Custom Logging) y mensajes de debug (Output List Messages) con scripts de  SSIS</title><content type='html'>Uno de los problemas más comunes en el desarrollo de paquetes SSIS es que no se puede hace debug en cada paso que se realiza. Sólo en el flujo de control, en las tareas de script, se puede depurar con el debugger integrado del designer,pero en la mayoría de los casos no tendremos suficiente. &lt;br /&gt;En un entorno de pruebas nos interesará, ya que no podremos hacer debug, como mínimo tener un buen sistema de logging para detectar posibles fallos. Veremos cómo se puede habilitar el logging en el paquete, registrar los mensajes de los componentes y conectarse con un proveedor de logging para guardar los mensajes en una base de datos SQL Server, un archivo de texto, etc, pero ¿y si queremos acceder a nuestros mensajes personalizados en el registro? &lt;br /&gt;&lt;br /&gt;La respuesta es que podemos utilizar componentes y tareas de script para hacer un logging más personalizado y útil. &lt;br /&gt;Opcionalmente, también podríamos visualizar de una forma diferente esta información mediante los eventos de Visual Studio. Así, los mensajes estarían disponibles en la vista de "Output List" de Visual Studio. &lt;br /&gt;&lt;br /&gt;Para registrar estos mensajes no hay más que añadir estas declaraciones VB en nuestros scripts: &lt;br /&gt;&lt;br /&gt;En los componentes 'Script Component' (Data Flow Tasks):&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;Me.Log("This is a logging message in a DFT", 0, Nothing)&lt;br /&gt;Me.ComponentMetaData.FireInformation(0, "ComponentName", "This is an information message in a DFT", Nothing, Nothing, False)&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;En las tareas 'script tasks' (Control Flow): &lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;Dts.Log("This is a log message in a Control Flow", 0, Nothing)&lt;br /&gt;Dts.Events.FireInformation(0, "ComponentName", "This is an information message in a Control Flow", Nothing, Nothing, False)&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;El paso final es habilitar el logging en el paquete, mediante el menú SSIS -&gt; Logging. Hay que añadir un 'Logging Provider' y comprobar que están habilitadas tanto los check ScriptComponentLogEntry para el 'Script Component' de DFT como la ScriptTaskLogEntry para la 'Script Task'. &lt;br /&gt;&lt;br /&gt;Podemos ver los resultados en la siguiente captura de pantalla.&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1pWkP9Tt94oF3jNvZt8N2BgycE_BQismnq5q2Zce6ZRHX30lptaAgYKRUb04zJyHuxG9AwiORkbzvZnLdaS2SN141-WSO7xvqA/Logging.png"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1pGTHPOPJ4yRMEzHolbJWiwgtWnEbqUhOaP0IdN7mBWTYzsKk8Vz0kgM61lEvPEl5JqMSJYBFw-CQHo0KvpNFI3UqacBaw9OB4/LoggingMini.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-298683739842626087?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/298683739842626087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/298683739842626087'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/09/custom-logging-and-output-list-messages.html' title='Logging personalizado (Custom Logging) y mensajes de debug (Output List Messages) con scripts de  SSIS'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-6721263636844741146</id><published>2008-08-28T12:27:00.001+02:00</published><updated>2008-12-04T16:41:54.426+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Null Value'/><category scheme='http://www.blogger.com/atom/ns#' term='Lookup Component'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Let the Null Values pass through the Lookup transformation in SSIS</title><content type='html'>After the summer, here I am to communicate something that surprises me and it can be useful for someone (I hope).&lt;br /&gt;When we use the &lt;b&gt;lookup component&lt;/b&gt; to retrieve values from another OLEDB source, we always hope that all entries will match with a row in the lookup table. When this situation doesn't happen, we have the ability to let the row pass the lookup component with a &lt;b&gt;null value&lt;/b&gt; in the lookup fields.&lt;br /&gt;But what if we want to have a different behavior for the null values that come from the source pipeline? We can have the next situation: &lt;br /&gt;We are translating some category codes from the products source table to a common set of new category codes. We have a translation table that will match every category source code with a new one. But we know that some rows from the source system come with a null value in the category field. For these rows, we want a &lt;b&gt;'Not Available'&lt;/b&gt; as translated value.&lt;br /&gt;The only thing that we should do to get this behavior in the SSIS Lookup component is to perform this little trick into the lookup component statement:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;select code, translation from CodeTable&lt;br /&gt;union all&lt;br /&gt;select null, 'Not Available'&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;As lookup component is able to match null values, the rows with a null value in the category field will be translated into the 'Not Available' value, just &lt;b&gt;as we wanted&lt;/b&gt;.&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-6721263636844741146?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/6721263636844741146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/6721263636844741146'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/08/let-null-values-pass-through-lookup.html' title='Let the Null Values pass through the Lookup transformation in SSIS'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-1489630393785518284</id><published>2008-06-29T18:01:00.002+02:00</published><updated>2009-10-28T16:28:57.463+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Configuration'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS'/><category scheme='http://www.blogger.com/atom/ns#' term='Sensitive'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='VSTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>SSIS, VSTS and Sensitive Information</title><content type='html'>Hello everybody.&lt;br /&gt;I have been testing for a long time what is the best approach to &lt;b&gt;share SSIS packages&lt;/b&gt; between developers in a wide developing team. The best solution for controlling versions of SSIS packages is, without a doubt, &lt;b&gt;Visual Studio Team System&lt;/b&gt;. With this tool the developers have full control of versions, branches, documentation, etc.&lt;br /&gt;But there's an issue when we share a SSIS package in a environment like this. SSIS encrypts all sensitive information about the package (passwords basically). By default, SSIS encrypts this sensitive information with a key that depends on the machine that contains the package. When the package is saved and another developer tries to edit it, SSIS tries to decrypt the package with the wrong key and fails.&lt;br /&gt;There are &lt;b&gt;two possible solutions&lt;/b&gt; to this issue:&lt;br /&gt;1) Set the ProtectionLevel of the package to EncryptSensitiveWithPassword and manually enter a password and share it with all developers. This approach allows the programmers to validate the package in design time and save the sensitive information inside the package. This approach has the inconvenient that every time that a developer opens a package, it is mandatory to enter the correct password. If we have 10 packages opened in a SSIS project, the developer will have to enter the password 10 times before starting to program.&lt;br /&gt;&lt;p class="link"&gt;&lt;a href="http://lgtpia.blu.livefilestore.com/y1pdJ94rPwCTACUMlEdJcUvFNU4pcA1P7IdR6MejEGYh78IV6PQry5kv5hzWA8COs3IJ_gudFyZ0ASbB3Rg3MOFlmYzVdp0lFAw/ProtectionLevel.png"&gt;&lt;img style="border: none" src="http://lgtpia.blu.livefilestore.com/y1p-d8Nex7Dv_yt9EKyHvU9pvHPaCc4rPKi7s5VZM5Xk6dHDq569GvlskpxZhUHlNG7r0i-L0nwRp3LlTLdUl-RZpMcMPrPek1q/ProtectionLevelMini.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;2) Set the ProtectionLevel of the package to DontSaveSensitive, use Package Configurations and set the DelayValidation property to True. With this approach the developers can save the sensitive information in XML configuration files, and there's no need to supply any password. Using package configurations is also considered a best practice by Microsoft experts.&lt;br /&gt;&lt;p class="link"&gt;&lt;a href="http://lgtpia.blu.livefilestore.com/y1pGXD97VqgztJc8YZTtX4-pwwHfFXulywwAdE2r4aQSFAzz29mtZ0vLRpdEDAoCBrboPrRZ5lxNNiMVxN1BdJN7Pg99xtMJiQQ/PackageConfig.png"&gt;&lt;img style="border: none" src="http://lgtpia.blu.livefilestore.com/y1pBnnWoQnsF1FTOfaCK3bi7DTbCoiAY8jYQWhOJjxH4ixq7LFPwx-KXQouD0u-N8zuQ7KFMxGcbdL5l3UX3SKtkPpT2vNdA0-x/PackageConfigMini.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;In my opinion, the &lt;b&gt;best solution&lt;/b&gt; in most cases will be the second one. In addition to the control over the sensitive information, we will have an easier way to move the package throughout environments (developing, testing, UAT, pre-production and production).&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-1489630393785518284?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/1489630393785518284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/1489630393785518284'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/06/ssis-vsts-and-sensitive-information.html' title='SSIS, VSTS and Sensitive Information'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-7315955587610273460</id><published>2008-05-07T08:26:00.004+02:00</published><updated>2008-12-04T16:41:00.982+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Warehouse'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Cleansing'/><category scheme='http://www.blogger.com/atom/ns#' term='T-SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Remove repeating rows with SQL Server 2005</title><content type='html'>When we are performing &lt;strong&gt;Data Cleansing&lt;/strong&gt; in a Data Warehouse environment, often we should take care of tables that has repeating rows (e.g. when there's no primary keys). There's no easy way to remove these &lt;strong&gt;repeating rows&lt;/strong&gt; in a single query since SQL Server 2005, by the OVER statement.&lt;br /&gt;I'll take a customers table to show how it works:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;SELECT * FROM (&lt;br /&gt;SELECT rn = row_number() OVER (PARTITION ON c.NIE ORDER BY c.DateModified), c.NIE, c.FirstName, c.Surname, ...&lt;br /&gt;FROM Customers c)&lt;br /&gt;WHERE rn = 1&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;This query will return to us only the last updated row of every customer, &lt;strong&gt;even&lt;/strong&gt; if the source table had &lt;strong&gt;more than one&lt;/strong&gt; row per customer and modified date.&lt;br /&gt;We can also perform delete statements like this:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;DELETE tbl FROM (&lt;br /&gt;SELECT rn = row_number() OVER (PARTITION ON c.NIE ORDER BY c.DateModified) FROM Customers c) AS tbl&lt;br /&gt;WHERE rn &lt;&gt; 1&lt;br /&gt;&lt;/p&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-7315955587610273460?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/7315955587610273460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/7315955587610273460'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/05/remove-repeating-rows-with-sql-server.html' title='Remove repeating rows with SQL Server 2005'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-8612932658354428310</id><published>2008-04-24T18:55:00.001+02:00</published><updated>2008-12-04T16:42:24.893+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CPM'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance Management'/><category scheme='http://www.blogger.com/atom/ns#' term='PerformancePoint Server 2007'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>PerformancePoint Server 2007 Training</title><content type='html'>The last week I had the opportunity to attend to a &lt;strong&gt;PerformancePoint Server 2007training&lt;/strong&gt;, performed by the MVPs of Solid Quality Mentors Spain.&lt;br /&gt;&lt;br /&gt;The experience (3 full days of theory and labs) was pretty exciting. I could learn the power of the &lt;strong&gt;Monitoring&lt;/strong&gt; Dashboards, and the sophisticated engine implemented by MS in the &lt;strong&gt;Planning&lt;/strong&gt; infrastructure. &lt;br /&gt;&lt;br /&gt;But there is a quite large list of constraints that we should take into account when we're planning to implement a project with this software. Here we have some samples:&lt;br /&gt;&lt;br /&gt;- It is not possible to reuse an existing Staging database, we're forced to use its own.&lt;br /&gt;- It is not possible to reuse an existing Time Dimension, we'll have to build a new one via the business modeler.&lt;br /&gt;- The tools provided by PerformancePoint Server to program the solution doesn't allow us to use any Source Code Control (neither VSS nor TFS).&lt;br /&gt;&lt;br /&gt;Despite this several constraints, that I hope and supose that in the next versions of the software will disapear, the product have plenty of advantages. Thus, I'm excited to get involved into a PerformancePoint BI project. I hope this will happen soon.&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-8612932658354428310?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/8612932658354428310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/8612932658354428310'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/04/performancepoint-server-2007-training.html' title='PerformancePoint Server 2007 Training'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-2487761912787693253</id><published>2008-04-03T21:09:00.001+02:00</published><updated>2008-12-04T16:42:34.895+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='DateTime'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Datetime transformation with SSIS</title><content type='html'>After doing a lot of failed transformation with some date columns in SSIS, with a very poor manually entered source data, I'll find the definitive solution to the datetime transformations from string.&lt;br /&gt;&lt;br /&gt;I have included a script component into the dataflow to perform the transformation, with the following code:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;Try&lt;br /&gt;Row.ConvertedDate = DateTime.Parse(Row.Date.Substring(0, 2) + "/" + Row.Date.Substring(2, 2) + "/" + Row.Date.Substring(4, 4))&lt;br /&gt;Catch&lt;br /&gt;Row.ConvertedDates = DateTime.MinValue&lt;br /&gt;End Try&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;With that approach you have the abbility of perform some &lt;b&gt;advanced transformations&lt;/b&gt; in the Catch statement.&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-2487761912787693253?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/2487761912787693253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/2487761912787693253'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/04/datetime-transformation-with-ssis.html' title='Datetime transformation with SSIS'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-362039097303967671</id><published>2008-03-27T01:30:00.002+01:00</published><updated>2009-10-28T16:33:49.486+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='64 bits Server'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>SSIS Error executing a package in a 64 bit server</title><content type='html'>Last week I get into trouble when I was developing a SQL Server Integration Services package to consolidate some information into a &lt;strong&gt;Data Warehouse&lt;/strong&gt;. The package consists of taking some information from text files, performs some transformation with the data via a script task, and updates a SQL table. When I execute the package in the development environment, it does with no problems.&lt;br /&gt;When I deploy the package into the production server, a four 64bit-processors machine, and executes it from a &lt;strong&gt;SQL Server Agent job&lt;/strong&gt;, I got the following error:&lt;br /&gt;&lt;p class="error"&gt;&lt;br /&gt; - DTS_E_PRODUCTLEVELTOLOW. The product level is insufficient for component ...&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p class="link"&gt;&lt;a href="http://lgtpia.blu.livefilestore.com/y1pHVJSb4hhwpio0foVUd9olroW9Fq3_Ung6bmorDY-z51EVwhmz2z1yz2NkS06OgmDWEJIkCAo7kWIjyolaUOTfxkDJjmcksF3/error32bits1.PNG"&gt;&lt;img style="border: none" src="http://lgtpia.blu.livefilestore.com/y1pFxzRDYhoD2yuz7w3CmlsaD3F9tTr1xvYqWbrTW6ZAPkuD-B8kvO0aw1sS6vE9kou3fiEKchSVEk5Ei3W-lrhmA9dwzRvALff/error32bits1mini.PNG"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;Digging and "googling", I discover, despite the confusing (or not?) message from SSIS, that the problem was that the script component of the package was pre-compiled for 32-bits and the server where I was trying to execute the package was a 64-bits one.&lt;br /&gt;&lt;br /&gt;There is an option of the "Script Component" that allows to compile in execution time the script, but it's a requirement to pre-compile the script if you want to execute them in a 64-bits server. Amazing!&lt;br /&gt;&lt;br /&gt;The workaround consists of executing the package with the dtexec utility instead of as a SSIS ordinary package. In all 64-bits SQL  Integration Services servers, the SQL installer installs two versions of the dtexec utility, one for the 64-bits package and another one for 32-bits compatibility executions.&lt;br /&gt;&lt;br /&gt;When defining the SQL Server Agent job that executes the process, we should change the job type to "Operating System" and type the command line arguments for the dtexec utility properly to execute the package.&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1p07lQ_K2TJWPSqFCQ2uthgtKhRyCVkZYw_MfmaaG5wSEP-vnC3rsvmnTwQImxSgmnUPi-39UDDAcV7q9RAyWk8L1OMtuENsM6/error32bits2.PNG"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1pHOxxQSg1gKhK0VFMf7q1lJiPdNBAjr219HPeWn61Scr7Jj0sEV1PB6G5w4Cw2CNIh4kd7k64ln259_wTqQ-ar7g93oiUegw3/error32bits2mini.PNG"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;The final command for the job was:&lt;br /&gt;&lt;p class="command"&gt;&lt;br /&gt;"D:\Program Files\Microsoft SQL Server (x86)\90\DTS\Binn\dtexec.exe" /DTS "\MSDB\TestSSIS32bits" /SERVER "." /CONFIGFILE "C:\Projects\TestSSIS32bits.dtsConfig"  /MAXCONCURRENT " -1 " /CHECKPOINTING OFF  /REPORTING V&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;and when I press the "Execute" button the result was SUCCESSFUL:&lt;br /&gt;&lt;p class="link"&gt;&lt;a class="link" href="http://lgtpia.blu.livefilestore.com/y1pLl6BXHZO1eeFZ2O4wRKAC9EEmHhWFfYyHojTsLbaQ6OVrZasIt6PWu81TevXAQS9h4bs_F8e91r5l6THMLA2SHrJxWJTbHGP/error32bits3.PNG"&gt;&lt;img src="http://lgtpia.blu.livefilestore.com/y1pHg5oFqeQV--SKaoRO2r6T5g-WbX2lmUq2G-8c7-0WtajujyIRWyNMhxbYzflUZWVmJh7jcfwlIrFC2Bpz8rrLt90FhcdStBH/error32bits3mini.PNG"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-362039097303967671?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/362039097303967671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/362039097303967671'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/04/ssis-error-executing-package-in-64-bit.html' title='SSIS Error executing a package in a 64 bit server'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-3314617885884180333</id><published>2008-03-17T04:29:00.001+01:00</published><updated>2008-12-04T16:42:56.966+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='MCP'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='MCITP'/><title type='text'>Microsoft Business Intelligence IT Professional</title><content type='html'>Last Friday, I past the exam 70-445 “Business Intelligence – Implementation and Maintenance”, becoming a &lt;strong&gt;Certified IT Professional&lt;/strong&gt; developing Business Intelligence solutions.&lt;br /&gt;&lt;br /&gt;The exam was finally not as difficult as I thought. I had read that this exam was more difficult to pass than 70-446, but both are similar, and someone who has past one of them, surely will pass the other one with a little effort.&lt;br /&gt;&lt;br /&gt;A great help to pass this exam was the &lt;strong&gt;Microsoft Training Kit&lt;/strong&gt;, which includes a set of possible exam questions and allows you to simulate an exam test.&lt;br /&gt;&lt;br /&gt;The next step, I hope, will be the “Microsoft Office PerformancePoint Server 2007 Applications” certification number 70-556.&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-3314617885884180333?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/3314617885884180333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/3314617885884180333'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/04/microsoft-business-intelligence-it.html' title='Microsoft Business Intelligence IT Professional'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4398803826831219104.post-523288317449146559</id><published>2008-03-06T06:19:00.001+01:00</published><updated>2008-12-04T16:43:08.679+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Business Intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>First shot</title><content type='html'>This Wednesday I have finally decided to create my blog, mainly to share my professional experiences in my daily work in "Raona Enginyers", a software engineering company with a high degree of &lt;strong&gt;technological knowledge&lt;/strong&gt;, especially with Microsoft technologies.&lt;br /&gt;&lt;br /&gt;I currently work as a technology specialist in &lt;strong&gt;Business Intelligence&lt;/strong&gt; projects, and split myself to be an &lt;strong&gt;Account Manager&lt;/strong&gt; at the same time. This blog is specially intended to people that has a truly passion about this kind of job, like I have.&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4398803826831219104-523288317449146559?l=microsoft-business-intelligence.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/523288317449146559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4398803826831219104/posts/default/523288317449146559'/><link rel='alternate' type='text/html' href='http://microsoft-business-intelligence.blogspot.com/2008/03/first-shot.html' title='First shot'/><author><name>Samuel Casanova</name><uri>http://www.blogger.com/profile/11574017408168964217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
