<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>El aprendiz de brujo </title><link>http://geeks.ms/blogs/lmblanco/default.aspx</link><description>El blog de Luis Miguel Blanco con hechizos, conjuros y sortilegios varios sobre la plataforma .NET y Business Intelligence
   &lt;img src="http://geeks.ms/blogs/lmblanco/ImgEnl/HatWand.jpg" style="border-style:none;vertical-align:middle;" alt="" /&gt;
</description><dc:language /><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Totales parciales con SUMMARIZE. Profundizando en el uso de DAX como lenguaje de consulta (y 9)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/05/15/totales-parciales-con-summarize-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-y-9.aspx</link><pubDate>Wed, 15 May 2013 17:16:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:209473</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=209473</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=209473</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/05/15/totales-parciales-con-summarize-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-y-9.aspx#comments</comments><description>&lt;p&gt;La cl&amp;aacute;usula &lt;a href="http://technet.microsoft.com/en-us/library/gg492171.aspx"&gt;ROLLUP&lt;/a&gt; perteneciente a la funci&amp;oacute;n SUMMARIZE genera, en las columnas de agregaci&amp;oacute;n que especifiquemos, filas adicionales de resultados acumulados (totales parciales) para las columnas num&amp;eacute;ricas utilizadas en la consulta.&lt;/p&gt;
&lt;p&gt;A modo de ejemplo, en la siguiente consulta utilizamos ROLLUP para la columna StoreType de la tabla DimStore, por lo que obtendremos, adem&amp;aacute;s de las cifras de venta por tipo de almac&amp;eacute;n, una &amp;uacute;ltima fila adicional con el total de las ventas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]) &lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_32.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Partiendo de este resultado, supongamos ahora que necesitamos que los tipos de almac&amp;eacute;n aparezcan ordenados, pero manteniendo la fila de total al final. Si usamos la cl&amp;aacute;usula ORDER BY en la consulta, el resultado no ser&amp;aacute; totalmente satisfactorio, ya que&amp;nbsp; se ordenar&amp;aacute;n los nombres, pero la fila de total quedar&amp;aacute; al principio.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;)&lt;br /&gt;ORDER BY [StoreType]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_33.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Aplicando el modificador DESC a la cl&amp;aacute;usula ORDER BY solucionamos el problema solamente en parte, ya que conseguimos que el total vuelva a colocarse al final del conjunto de resultados, pero como es l&amp;oacute;gico, los nombres quedan ordenados en sentido descendente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;)&lt;br /&gt;ORDER BY [StoreType] DESC&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_34.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Controlando la ubicaci&amp;oacute;n de los acumulados mediante ISSUBTOTAL&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si queremos ordenar los nombres en sentido ascendente, pero manteniendo la ubicaci&amp;oacute;n del total al final, debemos recurrir a &lt;a href="http://technet.microsoft.com/en-us/library/gg492171.aspx"&gt;ISSUBTOTAL&lt;/a&gt;, otra de las cl&amp;aacute;usulas de SUMMARIZE, la cual crea una columna de tipo l&amp;oacute;gico, en la que cada valor nos indica si la fila actual del conjunto de resultados corresponde a un acumulado (total parcial) o bien se trata de una fila normal de datos. El truco en este caso reside en aplicar una doble ordenaci&amp;oacute;n: primero por la columna de ISSUBTOTAL y a continuaci&amp;oacute;n por la de datos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]),&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Subtotal_StoreType&amp;quot;, ISSUBTOTAL(&amp;#39;DimStore&amp;#39;[StoreType])&lt;br /&gt;)&lt;br /&gt;ORDER BY [Subtotal_StoreType],[StoreType]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_35.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ahora vamos a a&amp;ntilde;adir la columna ContinentName, de la tabla DimGeography, como nueva columna de agrupaci&amp;oacute;n a la consulta. De esta manera, cada fila de acumulado resultante se corresponder&amp;aacute; con el total de ventas de un continente para todos los tipos de almac&amp;eacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[ContinentName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_36.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La interpretaci&amp;oacute;n de los datos que obtenemos, no obstante, es poco amigable, por lo que nuevamente usaremos ISSUBTOTAL y ordenaremos las columnas tal y como muestra el siguiente bloque de c&amp;oacute;digo, consiguiendo que las filas de acumulado se sit&amp;uacute;en proporcionando la informaci&amp;oacute;n de un modo m&amp;aacute;s legible.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[ContinentName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Subtotal_StoreType&amp;quot;, ISSUBTOTAL(&amp;#39;DimStore&amp;#39;[StoreType])&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName], [Subtotal_StoreType], [StoreType]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_37.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ya que ROLLUP admite m&amp;aacute;s de una columna de agregaci&amp;oacute;n como par&amp;aacute;metro, vamos a a&amp;ntilde;adirle la columna ContinentName para obtener en esta ocasi&amp;oacute;n, adem&amp;aacute;s de los acumulados anteriormente mencionados, una nueva fila de total con el importe de las ventas para todos los tipos de almac&amp;eacute;n y continentes. Al mismo tiempo crearemos con ISSUBTOTAL sendas columnas para StoreType y ContinentName, que junto a un adecuado orden facilitar&amp;aacute;n la lectura de los datos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(&amp;#39;DimStore&amp;#39;[StoreType], &amp;#39;DimGeography&amp;#39;[ContinentName]),&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Subtotal_StoreType&amp;quot;, ISSUBTOTAL(&amp;#39;DimStore&amp;#39;[StoreType]),&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Subtotal_ContinentName&amp;quot;, ISSUBTOTAL(&amp;#39;DimGeography&amp;#39;[ContinentName])&lt;br /&gt;)&lt;br /&gt;ORDER BY [Subtotal_StoreType], [StoreType], [Subtotal_ContinentName], [ContinentName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_38.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Agrupar los acumulados con ROLLUPGROUP&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A pesar de existir la posibilidad de utilizar varias columnas con ROLLUP, en determinadas situaciones quiz&amp;aacute; nos interese tener una &amp;uacute;nica fila de acumulado para todas las columnas de agregaci&amp;oacute;n incluidas en esta cl&amp;aacute;usula, lo que podemos lograr&amp;nbsp; mediante &lt;a href="http://technet.microsoft.com/en-us/library/gg492171.aspx"&gt;ROLLUPGROUP&lt;/a&gt;, otra de las cl&amp;aacute;usulas de SUMMARIZE.&lt;/p&gt;
&lt;p&gt;Esta cl&amp;aacute;usula se utiliza como par&amp;aacute;metro de ROLLUP, colocando las columnas de agregaci&amp;oacute;n como par&amp;aacute;metros de la llamada a la funci&amp;oacute;n ROLLUPGROUP.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROLLUP(ROLLUPGROUP(&amp;#39;DimStore&amp;#39;[StoreType], &amp;#39;DimGeography&amp;#39;[ContinentName])),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Subtotal_StoreType&amp;quot;, ISSUBTOTAL(&amp;#39;DimStore&amp;#39;[StoreType])&lt;br /&gt;)&lt;br /&gt;ORDER BY [Subtotal_StoreType], [StoreType], [ContinentName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_39.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Cabe destacar que la informaci&amp;oacute;n sobre ROLLUPGROUP disponible en la documentaci&amp;oacute;n online de la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/gg492171.aspx"&gt;SUMMARIZE&lt;/a&gt; es una aportaci&amp;oacute;n de &lt;a href="http://sqlblog.com/blogs/marco_russo/"&gt;Marco Russo&lt;/a&gt;, puesto que dicha entrada, correspondiente a la &lt;a href="http://technet.microsoft.com/en-us/library/ee634396.aspx"&gt;referencia&lt;/a&gt; de las funciones del lenguaje DAX, no dispon&amp;iacute;a inicialmente de rese&amp;ntilde;a alguna acerca de esta cl&amp;aacute;usula.&lt;/p&gt;
&lt;p&gt;Para lograr un comportamiento similar en Transact-SQL haremos uso del operador ROLLUP cuando especifiquemos las columnas a agrupar, as&amp;iacute; como de la funci&amp;oacute;n GROUPING en la lista de columnas a mostrar de la instrucci&amp;oacute;n SELECT.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT&lt;br /&gt;CASE&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHEN (GROUPING(StoreType)=1) THEN &amp;#39;--Total General--&amp;#39;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE StoreType&lt;br /&gt;END AS StoreType,&lt;br /&gt;CASE&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHEN (GROUPING(ContinentName)=1) THEN &amp;#39;--Acumulado por tipo almac&amp;eacute;n--&amp;#39;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE ContinentName&lt;br /&gt;END AS ContinentName,&lt;br /&gt;SUM(SalesAmount) AS Ventas&lt;br /&gt;FROM DimStore&lt;br /&gt;INNER JOIN DimGeography&lt;br /&gt;ON DimStore.GeographyKey = DimGeography.GeographyKey&lt;br /&gt;INNER JOIN FactSales&lt;br /&gt;ON DimStore.StoreKey = FactSales.StoreKey&lt;br /&gt;GROUP BY StoreType, ContinentName WITH ROLLUP&lt;br /&gt;ORDER BY StoreType, GROUPING(ContinentName), ContinentName&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Y llegados a este punto damos por concluida esta serie de art&amp;iacute;culos en los que hemos expuesto diversas t&amp;eacute;cnicas para la creaci&amp;oacute;n de consultas contra modelos tabulares empleando el lenguaje DAX, espero que os resulten de utilidad.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=209473" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Columnas de agrupación en SUMMARIZE con tablas no relacionadas. Profundizando en el uso de DAX como lenguaje de consulta (8)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/05/07/columnas-de-agrupaci-243-n-en-summarize-con-tablas-no-relacionadas-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-8.aspx</link><pubDate>Tue, 07 May 2013 18:45:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:209414</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=209414</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=209414</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/05/07/columnas-de-agrupaci-243-n-en-summarize-con-tablas-no-relacionadas-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-8.aspx#comments</comments><description>&lt;p&gt;Si las tablas de las columnas empleadas en la consulta con SUMMARIZE no est&amp;aacute;n relacionadas se producir&amp;aacute; un error, como vemos en el siguiente bloque de c&amp;oacute;digo, donde combinamos las columnas StoreType y BrandName de las tablas DimStore y DimProduct, para obtener las ventas realizadas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;[StoreType],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimProduct&amp;#39;[BrandName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_27.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tal y como se explica en el mensaje de error, la columna BrandName no existe en la tabla de entrada DimStore, utilizada como primer par&amp;aacute;metro de la funci&amp;oacute;n SUMMARIZE; aunque en este caso ser&amp;iacute;a m&amp;aacute;s correcto decir que la tabla DimProduct, que contiene la columna BrandName, no est&amp;aacute; relacionada con la tabla de entrada usada en la consulta. &lt;/p&gt;
&lt;p&gt;Si el primer par&amp;aacute;metro de SUMMARIZE representa una tabla con las columnas a visualizar (directa o indirectamente a trav&amp;eacute;s de relaciones), en el caso de que no existan relaciones con las tablas necesarias podemos crear una tabla al vuelo con las columnas que tenemos que mostrar empleando la funci&amp;oacute;n GENERATE.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GENERATE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StoreType],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [BrandName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas tipo almac&amp;eacute;n marca producto&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;)&lt;br /&gt;ORDER BY [StoreType],[BrandName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_28.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el caso de que el n&amp;uacute;mero de columnas sin relacionar que tengamos que presentar sea superior a dos, podemos optar por la funci&amp;oacute;n CROSSJOIN para crear la tabla de entrada utilizada por SUMMARIZE, como vemos en la siguiente consulta, donde creamos una medida calculada para realizar la suma de las ventas, a la que aplicaremos un formato monetario, y que emplearemos en una condici&amp;oacute;n de filtro para evitar mostrar importes vac&amp;iacute;os.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DEFINE&lt;br /&gt;MEASURE &amp;#39;FactSales&amp;#39;[Ventas] = SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CROSSJOIN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StoreType],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [BrandName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [CalendarYear],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas tipo almac&amp;eacute;n-marca producto-a&amp;ntilde;o venta&amp;quot;, FORMAT(&amp;#39;FactSales&amp;#39;[Ventas], &amp;quot;Currency&amp;quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NOT(ISBLANK([Ventas]))&lt;br /&gt;)&lt;br /&gt;ORDER BY [StoreType],[BrandName],[CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_29.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Partiendo del anterior resultado, supongamos ahora que necesitamos calcular el porcentaje que la combinaci&amp;oacute;n de ventas por tipo de almac&amp;eacute;n, marca de producto y a&amp;ntilde;o de venta ha supuesto con respecto al total de las ventas realizadas.&lt;/p&gt;
&lt;p&gt;Para obtener estos resultados precisamos a&amp;ntilde;adir al c&amp;oacute;digo de la consulta dos nuevas medidas calculadas: la primera, a la que llamaremos VentasTotales, realizar&amp;aacute; mediante la funci&amp;oacute;n SUMX la suma de la columna SalesAmount para todas las filas de la tabla FactSales; empleando la funci&amp;oacute;n ALL para ignorar cualquier filtro que pudiera encontrarse activo.&lt;/p&gt;
&lt;p&gt;La segunda medida, PorcentajeVentas, efectuar&amp;aacute; la operaci&amp;oacute;n encargada de calcular el porcentaje de las ventas realizadas. Dicho valor ser&amp;aacute; convenientemente formateado cuando lo mostremos junto al resto de columnas de la consulta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DEFINE&lt;br /&gt;MEASURE &amp;#39;FactSales&amp;#39;[Ventas] = SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;MEASURE &amp;#39;FactSales&amp;#39;[VentasTotales] = SUMX(ALL(&amp;#39;FactSales&amp;#39;), &amp;#39;FactSales&amp;#39;[SalesAmount]) &lt;br /&gt;MEASURE &amp;#39;FactSales&amp;#39;[PorcentajeVentas] = (&amp;#39;FactSales&amp;#39;[Ventas] / &amp;#39;FactSales&amp;#39;[VentasTotales])&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CROSSJOIN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StoreType],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [BrandName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [CalendarYear],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas tipo almac&amp;eacute;n-marca producto-a&amp;ntilde;o venta&amp;quot;, FORMAT(&amp;#39;FactSales&amp;#39;[Ventas], &amp;quot;Currency&amp;quot;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas totales&amp;quot;, &amp;#39;FactSales&amp;#39;[VentasTotales],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Porcentaje ventas&amp;quot;, FORMAT(&amp;#39;FactSales&amp;#39;[PorcentajeVentas], &amp;quot;Percent&amp;quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NOT(ISBLANK([Ventas]))&lt;br /&gt;)&lt;br /&gt;ORDER BY [StoreType],[BrandName],[CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_30.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Aunque la medida calculada VentasTotales se visualiza junto al resto de las columnas, podr&amp;iacute;a perfectamente permanecer oculta, ya que su finalidad consiste en actuar como operando para hallar el porcentaje de las ventas.&lt;/p&gt;
&lt;p&gt;Para obtener este mismo resultado mediante SQL, tendremos que establecer, al igual que en anteriores ejemplos, las combinaciones necesarias entre las tablas implicadas en la consulta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT StoreType, BrandName, CalendarYear,&lt;br /&gt;SUM(SalesAmount) AS [Ventas tipo almac&amp;eacute;n-marca producto-a&amp;ntilde;o venta],&lt;br /&gt;(SELECT SUM(SalesAmount) FROM FactSales) AS [Ventas totales],&lt;br /&gt;FORMAT( ( SUM(SalesAmount) / (SELECT SUM(SalesAmount) FROM FactSales) ) , &amp;#39;P&amp;#39;, &amp;#39;ES-ES&amp;#39; )&amp;nbsp; AS [Porcentaje ventas]&lt;br /&gt;FROM DimStore&lt;br /&gt;INNER JOIN FactSales&lt;br /&gt;ON DimStore.StoreKey = FactSales.StoreKey&lt;br /&gt;INNER JOIN DimProduct&lt;br /&gt;ON FactSales.ProductKey = DimProduct.ProductKey&lt;br /&gt;INNER JOIN DimDate&lt;br /&gt;ON FactSales.DateKey = DimDate.Datekey&lt;br /&gt;GROUP BY StoreType, BrandName, CalendarYear&lt;br /&gt;ORDER BY StoreType, BrandName, CalendarYear&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Empleando la tabla de resultados num&amp;eacute;ricos como tabla de entrada&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En los &amp;uacute;ltimos ejemplos de SUMMARIZE hemos planteado la manera de abordar la creaci&amp;oacute;n de una consulta introduciendo un problema consistente en la inexistencia de relaciones entre la tabla de entrada y el resto de tablas de las columnas de agregaci&amp;oacute;n implicadas en dicha consulta, lo cual nos llevaba a recurrir a soluciones un tanto artificiosas, tales como el empleo de las funciones GENERATE o CROSSJOIN en el c&amp;oacute;digo a escribir.&lt;/p&gt;
&lt;p&gt;Observando las caracter&amp;iacute;sticas de estas consultas nos percataremos de que la tabla FactSales, empleada para calcular la suma de ventas, se encuentra relacionada con las tablas utilizadas para las columnas de agregaci&amp;oacute;n. Si a esto unimos la capacidad de utilizar FactSales como tabla de entrada en SUMMARIZE, podremos construir una consulta m&amp;aacute;s simple que evite el uso de trucos rebuscados. Como ventaja a&amp;ntilde;adida, esta consulta no devuelve filas con la columna de ventas vac&amp;iacute;a, lo que tambi&amp;eacute;n nos libera de aplicar el correspondiente filtro.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;FactSales&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;[StoreType],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimProduct&amp;#39;[BrandName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimDate&amp;#39;[CalendarYear],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;, FORMAT(SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]), &amp;quot;Currency&amp;quot;)&lt;br /&gt;)&lt;br /&gt;ORDER BY [StoreType],[BrandName],[CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_31.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=209414" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Combinación de múltiples tablas con SUMMARIZE. Profundizando en el uso de DAX como lenguaje de consulta (7)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/04/24/combinaci-243-n-de-m-250-ltiples-tablas-con-summarize-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-7.aspx</link><pubDate>Wed, 24 Apr 2013 17:59:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:209278</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=209278</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=209278</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/04/24/combinaci-243-n-de-m-250-ltiples-tablas-con-summarize-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-7.aspx#comments</comments><description>&lt;p&gt;Las columnas de agrupaci&amp;oacute;n de los ejemplos con SUMMARIZE mostrados en la entrega anterior pertenec&amp;iacute;an a una misma tabla, lo cual puede resultar conveniente en determinados casos, pero con toda seguridad, en alg&amp;uacute;n momento nos encontraremos ante situaciones en las que tengamos que crear una consulta para visualizar columnas pertenecientes a diversas tablas del modelo.&lt;/p&gt;
&lt;p&gt;Gracias a la potencia que ofrece el mecanismo de relaciones del motor tabular, esta labor resulta tan simple como a&amp;ntilde;adir tales columnas en la lista de par&amp;aacute;metros de la funci&amp;oacute;n, siempre y cuando existan las oportunas relaciones entre las tablas integrantes de la consulta.&lt;/p&gt;
&lt;p&gt;Observando el diagrama de nuestro modelo de datos de ejemplo vemos que la tabla DimStore se relaciona con las tablas DimGeography, DimEmployee y FactSales, por lo que podemos construir una consulta con SUMMARIZE en la que ofrezcamos al usuario la suma de los descuentos sobre las ventas, agregada por el tipo de almac&amp;eacute;n, pa&amp;iacute;s y nombre del gerente del almac&amp;eacute;n que ha realizado la venta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;[StoreType],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[RegionCountryName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimEmployee&amp;#39;[FirstName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimEmployee&amp;#39;[LastName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Total descuentos&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[DiscountAmount])&lt;br /&gt;)&lt;br /&gt;ORDER BY [StoreType],[RegionCountryName],[FirstName],[LastName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_25.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En SQL esta consulta es muy similar a la anterior que hemos escrito en Transact, con alguna variaci&amp;oacute;n en las tablas a combinar.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT StoreType, RegionCountryName, FirstName, LastName,&lt;br /&gt;SUM(DiscountAmount) AS [Total descuentos]&lt;br /&gt;FROM DimStore&lt;br /&gt;INNER JOIN DimGeography&lt;br /&gt;ON DimStore.GeographyKey = DimGeography.GeographyKey&lt;br /&gt;INNER JOIN DimEmployee&lt;br /&gt;ON DimStore.StoreManager = DimEmployee.EmployeeKey&lt;br /&gt;INNER JOIN FactSales&lt;br /&gt;ON DimStore.StoreKey = FactSales.StoreKey&lt;br /&gt;GROUP BY StoreType, RegionCountryName, FirstName, LastName&lt;br /&gt;ORDER BY StoreType, RegionCountryName, FirstName, LastName&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En la tabla DimStore, la columna StoreManager representa al empleado de la organizaci&amp;oacute;n que realiza las funciones de gerente o director del almac&amp;eacute;n, existiendo la posibilidad de que un mismo gerente se encuentre al cargo de varios almacenes. Esto nos permite complicar un poco la consulta DAX anterior, de manera que los resultados visualizados se correspondan con los directores que administran m&amp;aacute;s de un almac&amp;eacute;n.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n mostramos nuevamente esta consulta con los retoques que acabamos de mencionar. Por un lado quitamos la columna StoreType de la tabla DimStore, ya que uno de los objetivos consiste en contar el n&amp;uacute;mero de almacenes a cargo de cada director, independientemente del tipo de almac&amp;eacute;n. Dicho recuento lo realizaremos empleando una medida calculada (cl&amp;aacute;usula DEFINE) con el nombre NumeroAlmacenes, que reutilizaremos en m&amp;aacute;s de un lugar de la consulta. La funci&amp;oacute;n FILTER, por otra parte, nos permitir&amp;aacute; establecer la condici&amp;oacute;n para obtener los gerentes a cargo de varios almacenes. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DEFINE&lt;br /&gt;MEASURE &amp;#39;DimStore&amp;#39;[NumeroAlmacenes] = COUNT(&amp;#39;DimStore&amp;#39;[StoreKey])&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[RegionCountryName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimEmployee&amp;#39;[FirstName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimEmployee&amp;#39;[LastName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Total descuentos&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[DiscountAmount]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;N&amp;uacute;mero almacenes gestionados&amp;quot;, &amp;#39;DimStore&amp;#39;[NumeroAlmacenes]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;[NumeroAlmacenes] &amp;gt; 1&lt;br /&gt;)&lt;br /&gt;ORDER BY [RegionCountryName],[FirstName],[LastName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_26.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Utilizando SQL resulta necesario escribir una mayor cantidad de c&amp;oacute;digo para conseguir este mismo resultado, como vemos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;WITH&lt;br /&gt;tblGerentes AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT StoreManager, COUNT(*) AS NumeroAlmacenes&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM DimStore&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GROUP BY StoreManager&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; HAVING COUNT(*) &amp;gt; 1&lt;br /&gt;),&lt;br /&gt;tblStore AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT StoreKey, GeographyKey, DimStore.StoreManager, tblGerentes.NumeroAlmacenes&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM DimStore&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN tblGerentes&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ON DimStore.StoreManager = tblGerentes.StoreManager&lt;br /&gt;)&lt;br /&gt;SELECT RegionCountryName, StoreManager, FirstName, LastName,&lt;br /&gt;SUM(DiscountAmount) AS [Total descuentos],&lt;br /&gt;NumeroAlmacenes AS [N&amp;uacute;mero almacenes gestionados]&lt;br /&gt;FROM tblStore&lt;br /&gt;INNER JOIN DimGeography&lt;br /&gt;ON tblStore.GeographyKey = DimGeography.GeographyKey&lt;br /&gt;INNER JOIN DimEmployee&lt;br /&gt;ON tblStore.StoreManager = DimEmployee.EmployeeKey&lt;br /&gt;INNER JOIN FactSales&lt;br /&gt;ON tblStore.StoreKey = FactSales.StoreKey&lt;br /&gt;GROUP BY RegionCountryName, StoreManager, FirstName, LastName, NumeroAlmacenes&lt;br /&gt;ORDER BY RegionCountryName, StoreManager, FirstName, LastName, NumeroAlmacenes&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En la siguiente entrega daremos otra vuelta de tuerca al uso de la funci&amp;oacute;n SUMMARIZE, mostrando el modo de resolver consultas en las que se encuentren involucradas tablas no relacionadas.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=209278" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Agrupación y agregación de columnas con la función SUMMARIZE. Profundizando en el uso de DAX como lenguaje de consulta (6)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/04/17/agrupaci-243-n-y-agregaci-243-n-de-columnas-con-la-funci-243-n-summarize-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-6.aspx</link><pubDate>Wed, 17 Apr 2013 17:29:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:209207</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=209207</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=209207</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/04/17/agrupaci-243-n-y-agregaci-243-n-de-columnas-con-la-funci-243-n-summarize-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-6.aspx#comments</comments><description>&lt;p&gt;La funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/gg492171.aspx"&gt;SUMMARIZE&lt;/a&gt; muestra los distintos valores de una o varias columnas (denominadas &lt;i&gt;columnas de agrupaci&amp;oacute;n&lt;/i&gt;) de una tabla, permitiendo adem&amp;aacute;s incluir expresiones que generen columnas calculadas, encargadas de devolver valores num&amp;eacute;ricos en base a las columnas de agrupaci&amp;oacute;n. Con ello logramos un comportamiento similar al obtenido mediante la cl&amp;aacute;usula GROUP BY de Transact-SQL.&lt;/p&gt;
&lt;p&gt;Comenzaremos nuestro periplo acerca del uso de esta funci&amp;oacute;n con un ejemplo muy b&amp;aacute;sico: mostrar los distintos valores de la columna RegionCountryName, perteneciente a la tabla DimGeography.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[RegionCountryName]&lt;br /&gt;)&lt;br /&gt;ORDER BY [RegionCountryName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_23.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como es l&amp;oacute;gico, podemos utilizar varias de las columnas correspondientes a la tabla pasada en el primer par&amp;aacute;metro, tambi&amp;eacute;n denominada &lt;i&gt;tabla de entrada&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[ContinentName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[RegionCountryName]&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName],[RegionCountryName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para conseguir un resultado equivalente en SQL podemos emplear GROUP BY, tal y como hemos mencionado anteriormente, o tambi&amp;eacute;n la cl&amp;aacute;usula DISTINCT, ya que hasta el momento no estamos usando una operaci&amp;oacute;n de agregado como COUNT, SUM, etc., sobre el conjunto de resultados.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT ContinentName, RegionCountryName &lt;br /&gt;FROM DimGeography&lt;br /&gt;GROUP BY ContinentName, RegionCountryName&lt;br /&gt;ORDER BY ContinentName, RegionCountryName&lt;/p&gt;
&lt;p&gt;--//////////////////////////////////////////////&lt;/p&gt;
&lt;p&gt;SELECT DISTINCT ContinentName, RegionCountryName &lt;br /&gt;FROM DimGeography&lt;br /&gt;ORDER BY ContinentName, RegionCountryName&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Supongamos ahora que de este resultado nos interesar&amp;iacute;a saber la cantidad de unidades vendidas para cada una de las combinaciones de continente y pa&amp;iacute;s. Para ello escribiremos una expresi&amp;oacute;n que utilice la funci&amp;oacute;n SUM aplicada a la columna SalesQuantity de la tabla FactSales, y que a&amp;ntilde;adiremos a SUMMARIZE como &amp;uacute;ltimo par&amp;aacute;metro.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[ContinentName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[RegionCountryName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Cantidades vendidas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesQuantity])&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName],[RegionCountryName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_24.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el caso de que necesitemos m&amp;aacute;s columnas calculadas iremos a&amp;ntilde;adiendo las expresiones correspondientes a las mismas como par&amp;aacute;metros adicionales al final de la funci&amp;oacute;n, tal y como vemos a continuaci&amp;oacute;n, donde agregamos dos medidas para obtener el importe de venta y las ventas menos el descuento aplicado.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;SUMMARIZE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[ContinentName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimGeography&amp;#39;[RegionCountryName],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Cantidades vendidas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesQuantity]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Importe ventas&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Venta con descuento&amp;quot;, SUMX(&amp;#39;FactSales&amp;#39;, &amp;#39;FactSales&amp;#39;[SalesAmount] - &amp;#39;FactSales&amp;#39;[DiscountAmount])&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName],[RegionCountryName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Al emplear una sentencia SQL para obtener un resultado equivalente ahora s&amp;iacute; ser&amp;aacute; necesario el uso de GROUP BY, dado que aplicamos diversas operaciones de agregado (suma) sobre varias columnas, as&amp;iacute; como la combinaci&amp;oacute;n de la tabla DimGeography con DimStore y FactSales, para que las columnas num&amp;eacute;ricas reflejen los valores correctos para cada continente y pa&amp;iacute;s.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT ContinentName, RegionCountryName,&lt;br /&gt;SUM(SalesQuantity) AS [Cantidades vendidas],&lt;br /&gt;SUM(SalesAmount) AS [Importe ventas],&lt;br /&gt;(SUM(SalesAmount) - SUM(DiscountAmount)) AS [Venta con descuento]&lt;br /&gt;FROM DimGeography&lt;br /&gt;INNER JOIN DimStore&lt;br /&gt;ON DimGeography.GeographyKey = DimStore.GeographyKey&lt;br /&gt;INNER JOIN FactSales&lt;br /&gt;ON DimStore.StoreKey = FactSales.StoreKey&lt;br /&gt;GROUP BY ContinentName, RegionCountryName&lt;br /&gt;ORDER BY ContinentName, RegionCountryName&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En la siguiente parte de esta serie abordaremos la forma de mostrar columnas de agrupaci&amp;oacute;n procedentes de m&amp;uacute;ltiples tablas empleando SUMMARIZE.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=209207" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Obtención de N filas con TOPN. Profundizando en el uso de DAX como lenguaje de consulta (5)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/04/10/obtenci-243-n-de-n-filas-con-topn-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-5.aspx</link><pubDate>Wed, 10 Apr 2013 20:53:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:209135</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=209135</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=209135</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/04/10/obtenci-243-n-de-n-filas-con-topn-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-5.aspx#comments</comments><description>&lt;p&gt;La funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/gg492198.aspx"&gt;TOPN&lt;/a&gt; devuelve un subconjunto de una cantidad determinada de las primeras filas pertenecientes a una tabla, en base a una expresi&amp;oacute;n utilizada para ordenar dicha tabla.&lt;/p&gt;
&lt;p&gt;Como primer par&amp;aacute;metro pasaremos el n&amp;uacute;mero de filas a recuperar; en segundo lugar indicaremos la tabla de la que se obtendr&amp;aacute;n las filas; el tercer par&amp;aacute;metro corresponder&amp;aacute; a la expresi&amp;oacute;n que realizar&amp;aacute; la ordenaci&amp;oacute;n de las filas; y opcionalmente, en el cuarto par&amp;aacute;metro, pasaremos un n&amp;uacute;mero (0 &amp;oacute; 1) indicativo del sentido (ascendente o descendente) en que se realizar&amp;aacute; la ordenaci&amp;oacute;n especificada en el tercer par&amp;aacute;metro.&lt;/p&gt;
&lt;p&gt;Supongamos que de la tabla DimProduct queremos averiguar las siete marcas de productos (columna BrandName) que han generado m&amp;aacute;s ventas (tabla FactSales, columna SalesAmount). Comenzaremos nuestro an&amp;aacute;lisis del problema desde el motor relacional, ejecutando la siguiente consulta SQL, que nos devuelve todas las marcas de producto con sus totales de venta correspondientes.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;WITH tblMarcas AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT DP.BrandName,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM(FS.SalesAmount) AS VentasMarca&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM FactSales AS FS, DimProduct AS DP&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE FS.ProductKey = DP.ProductKey&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GROUP BY DP.BrandName&lt;br /&gt;)&lt;br /&gt;SELECT BrandName, FORMAT(VentasMarca, &amp;#39;C&amp;#39;, &amp;#39;es-es&amp;#39;) AS Ventas&lt;br /&gt;FROM tblMarcas&lt;br /&gt;ORDER BY VentasMarca DESC&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_20.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para obtener aqu&amp;iacute; las siete marcas con m&amp;aacute;s ventas, simplemente a&amp;ntilde;adiremos la part&amp;iacute;cula TOP junto a la cantidad de filas que necesitamos obtener.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;WITH tblMarcas AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT DP.BrandName,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM(FS.SalesAmount) AS VentasMarca&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM FactSales AS FS, DimProduct AS DP&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE FS.ProductKey = DP.ProductKey&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GROUP BY DP.BrandName&lt;br /&gt;)&lt;br /&gt;SELECT TOP 7 BrandName, FORMAT(VentasMarca, &amp;#39;C&amp;#39;, &amp;#39;es-es&amp;#39;) AS Ventas&lt;br /&gt;FROM tblMarcas&lt;br /&gt;ORDER BY VentasMarca DESC&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Vamos a realizar un primer intento para conseguir este mismo resultado en DAX, utilizando la funci&amp;oacute;n TOPN en la siguiente consulta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;TOPN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt;
&lt;p&gt;Los resultados, no obstante, no ser&amp;aacute;n nada satisfactorios porque, por un lado, obtenemos todos los nombres de marcas de producto, y por otro, no aparecen los importes de ventas por marca. Observando detenidamente la documentaci&amp;oacute;n de la funci&amp;oacute;n veremos que esto es completamente l&amp;oacute;gico, ya que TOPN devuelve las filas de la tabla pasada en el segundo par&amp;aacute;metro seg&amp;uacute;n el resultado de aplicar la expresi&amp;oacute;n del tercero.&lt;/p&gt;
&lt;p&gt;Como primer paso para acercarnos a la soluci&amp;oacute;n a&amp;ntilde;adiremos a la consulta una medida calculada, que ser&amp;aacute; la encargada de sumar la columna SalesAmount; esta medida la emplearemos a continuaci&amp;oacute;n como tercer par&amp;aacute;metro de TOPN.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DEFINE&lt;br /&gt;MEASURE DimProduct[VentasPorMarca] = SUM(FactSales[SalesAmount])&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;TOPN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DimProduct[VentasPorMarca],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_21.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Con esto casi hemos cumplido con nuestro objetivo, tan s&amp;oacute;lo nos falta visualizar la columna con los importes de ventas, para lo cual recurriremos a la funci&amp;oacute;n ADDCOLUMNS, a la que pasaremos como par&amp;aacute;metro la funci&amp;oacute;n TOPN y la expresi&amp;oacute;n con la columna calculada que realiza la suma de las ventas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DEFINE&lt;br /&gt;MEASURE &amp;#39;DimProduct&amp;#39;[VentasPorMarca] = SUM(&amp;#39;FactSales&amp;#39; [SalesAmount])&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TOPN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimProduct&amp;#39;[VentasPorMarca],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por nombre marca&amp;quot;, FORMAT(&amp;#39;DimProduct&amp;#39;[VentasPorMarca], &amp;quot;Currency&amp;quot;)&lt;br /&gt;)&lt;br /&gt;ORDER BY &amp;#39;DimProduct&amp;#39;[VentasPorMarca] DESC&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_22.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Aunque podamos estar acostumbrados al uso de la part&amp;iacute;cula TOP en Transact-SQL, en el contexto de las consultas y expresiones con DAX es probable que el empleo de TOPN no resulte tan intuitivo como a priori cabr&amp;iacute;a esperar. En este &lt;a href="http://www.powerpivotpro.com/2011/07/guest-post-topn-in-powerpivot-v2/"&gt;enlace&lt;/a&gt; se proporciona una explicaci&amp;oacute;n m&amp;aacute;s detallada sobre dicha funci&amp;oacute;n, y en este &lt;a href="http://bipassion.wordpress.com/2012/04/25/dax-topn-generate/"&gt;post&lt;/a&gt; se muestra un interesante caso de uso.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=209135" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>La función CROSSJOIN. Profundizando en el uso de DAX como lenguaje de consulta (4)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/04/02/la-funci-243-n-crossjoin-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-4.aspx</link><pubDate>Tue, 02 Apr 2013 20:39:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:209032</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=209032</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=209032</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/04/02/la-funci-243-n-crossjoin-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-4.aspx#comments</comments><description>&lt;p&gt;A ra&amp;iacute;z de las consultas desarrolladas en la entrega anterior, supongamos que ahora debemos visualizar, adem&amp;aacute;s de la marca del producto y el a&amp;ntilde;o de venta, el nombre del pa&amp;iacute;s y tipo de almac&amp;eacute;n en el que &amp;eacute;sta se ha producido; datos que encontramos en las tablas DimGeography y DimStore respectivamente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;CROSSJOIN. Aumentando la cantidad de tablas a combinar&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Puesto que la funci&amp;oacute;n GENERATE admite solamente dos tablas en su lista de par&amp;aacute;metros debemos modificar nuestra consulta, de forma que soporte la inclusi&amp;oacute;n de nuevas columnas, por lo que vamos a recurrir a la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/gg492168.aspx"&gt;CROSSJOIN&lt;/a&gt;, que al igual que GENERATE, realiza un producto cartesiano de las tablas que recibe como par&amp;aacute;metro, pero con la diferencia de poder utilizar m&amp;aacute;s de dos tablas, como vemos en la siguiente consulta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;CROSSJOIN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimGeography&amp;#39;[ContinentName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear])&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName], [StoreType], [BrandName], [CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_15.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para obtener el mismo resultado en Transact-SQL podemos utilizar la cl&amp;aacute;usula CROSS JOIN, pero con el inconveniente de que el tiempo de ejecuci&amp;oacute;n de la consulta ser&amp;aacute; notablemente mayor que en DAX.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT DISTINCT g.ContinentName,s.StoreType,p.BrandName,d.CalendarYear&lt;br /&gt;FROM DimGeography AS g&lt;br /&gt;CROSS JOIN DimStore AS s&lt;br /&gt;CROSS JOIN DimProduct AS p&lt;br /&gt;CROSS JOIN DimDate AS d&lt;br /&gt;ORDER BY g.ContinentName,s.StoreType,p.BrandName,d.CalendarYear&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para a&amp;ntilde;adir a la consulta DAX la columna con las cifras de ventas emplearemos ADDCOLUMNS como uno m&amp;aacute;s de los par&amp;aacute;metros de CROSSJOIN.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;CROSSJOIN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimGeography&amp;#39;[ContinentName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;,FORMAT(SUMX(RELATEDTABLE(FactSales), &amp;#39;FactSales&amp;#39;[SalesAmount]), &amp;quot;Currency&amp;quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName], [StoreType], [BrandName], [CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_16.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tras ejecutar la consulta, con toda seguridad habremos advertido que el c&amp;aacute;lculo resultante en la columna de ventas es incorrecto, ya que para cada fila &amp;uacute;nicamente se est&amp;aacute; teniendo en cuenta la columna &amp;#39;DimDate&amp;#39;[CalendarYear] al realizar la suma de &amp;#39;FactSales&amp;#39;[SalesAmount]. Este resultado para cada grupo de a&amp;ntilde;os es el mismo que si utiliz&amp;aacute;ramos la siguiente consulta SQL.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT YEAR(DateKey) AS A&amp;ntilde;oVenta, &lt;br /&gt;FORMAT(SUM(SalesAmount), &amp;#39;C&amp;#39;, &amp;#39;es-es&amp;#39;) AS ImporteVentas&lt;br /&gt;FROM FactSales&lt;br /&gt;GROUP BY YEAR(DateKey)&lt;br /&gt;ORDER BY YEAR(DateKey)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_17.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Sin embargo, nuestro objetivo consiste en efectuar la suma de &amp;#39;FactSales&amp;#39;[SalesAmount] para cada combinaci&amp;oacute;n de &amp;#39;DimGeography&amp;#39;[ContinentName], &amp;#39;DimStore&amp;#39;[StoreType], &amp;#39;DimProduct&amp;#39;[BrandName] y &amp;#39;DimDate&amp;#39;[CalendarYear]. Supongamos que tuvi&amp;eacute;ramos que construir esta consulta para ejecutarla en el motor relacional. La sentencia SQL a emplear, utilizando CTEs, ser&amp;iacute;a parecida a la siguiente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;WITH&lt;br /&gt;tblGeography AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT DISTINCT GeographyKey, ContinentName &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM DimGeography &lt;br /&gt;),&lt;br /&gt;tblStore AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT StoreKey, StoreType, tblGeography.ContinentName&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM DimStore&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN tblGeography&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ON DimStore.GeographyKey = tblGeography.GeographyKey&lt;br /&gt;),&lt;br /&gt;tblProduct AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT ProductKey, BrandName&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM DimProduct&lt;br /&gt;),&lt;br /&gt;tblDate AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT Datekey, CalendarYear&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM DimDate&lt;br /&gt;)&lt;br /&gt;SELECT ContinentName, StoreType, BrandName, CalendarYear, FORMAT(SUM(SalesAmount), &amp;#39;C&amp;#39;, &amp;#39;es-es&amp;#39;) AS Ventas&lt;br /&gt;FROM FactSales&lt;br /&gt;INNER JOIN tblStore&lt;br /&gt;ON FactSales.StoreKey = tblStore.StoreKey&lt;br /&gt;INNER JOIN tblProduct&lt;br /&gt;ON FactSales.ProductKey = tblProduct.ProductKey&lt;br /&gt;INNER JOIN tblDate&lt;br /&gt;ON FactSales.DateKey = tblDate.Datekey&lt;br /&gt;GROUP BY ContinentName, StoreType, BrandName, CalendarYear&lt;br /&gt;ORDER BY ContinentName, StoreType, BrandName, CalendarYear&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_18.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para obtener un resultado equivalente en DAX debemos cambiar la posici&amp;oacute;n de las funciones CROSSJOIN y ADDCOLUMNS dentro de la consulta.&lt;/p&gt;
&lt;p&gt;Como primer par&amp;aacute;metro de ADDCOLUMNS pasaremos la llamada a CROSSJOIN, y como segundo la expresi&amp;oacute;n que crea la columna calculada que realiza la suma de &amp;#39;FactSales&amp;#39;[SalesAmount]. Adicionalmente situaremos todo este c&amp;oacute;digo dentro de la funci&amp;oacute;n FILTER, a&amp;ntilde;adiendo una condici&amp;oacute;n para quitar las filas que carezcan de importe de venta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CROSSJOIN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimGeography&amp;#39;[ContinentName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;,FORMAT(SUMX(RELATEDTABLE(FactSales), &amp;#39;FactSales&amp;#39;[SalesAmount]), &amp;quot;Currency&amp;quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LEN([Ventas]) &amp;gt; 0&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName], [StoreType], [BrandName], [CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_19.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como alternativa a lo anterior podemos volver a usar GENERATE, pasando en el primer par&amp;aacute;metro la llamada a CROSSJOIN y en el segundo la funci&amp;oacute;n ADDCOLUMNS.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GENERATE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CROSSJOIN(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimGeography&amp;#39;[ContinentName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimStore&amp;#39;[StoreType]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas&amp;quot;,FORMAT(SUMX(RELATEDTABLE(FactSales), &amp;#39;FactSales&amp;#39;[SalesAmount]), &amp;quot;Currency&amp;quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LEN([Ventas]) &amp;gt; 0&lt;br /&gt;)&lt;br /&gt;ORDER BY [ContinentName], [StoreType], [BrandName], [CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=209032" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>La función GENERATE. Profundizando en el uso de DAX como lenguaje de consulta (3)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/03/19/la-funci-243-n-generate-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-3.aspx</link><pubDate>Tue, 19 Mar 2013 20:00:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:208887</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=208887</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=208887</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/03/19/la-funci-243-n-generate-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-3.aspx#comments</comments><description>&lt;p&gt;En la segunda parte de esta serie ilustr&amp;aacute;bamos c&amp;oacute;mo mediante el trabajo en conjunto de VALUES m&amp;aacute;s ADDCOLUMNS, logr&amp;aacute;bamos crear consultas cuyos resultados ofrecieran al mismo tiempo la informaci&amp;oacute;n de una tabla m&amp;aacute;s una operaci&amp;oacute;n de agregado sobre otra tabla relacionada.&lt;/p&gt;
&lt;p&gt;Pero habr&amp;aacute; ocasiones en que esto no sea suficiente, siendo necesario a&amp;ntilde;adir a la consulta datos de otras tablas del modelo, para ampliar y mejorar la informaci&amp;oacute;n proporcionada al usuario.&lt;/p&gt;
&lt;p&gt;Por ejemplo, tomando como punto de partida la consulta con la funci&amp;oacute;n VALUES de la entrega anterior, supongamos que adem&amp;aacute;s de la columna BrandName, necesitamos a&amp;ntilde;adir al resultado la columna CalendarYear de la tabla DimDate y un c&amp;aacute;lculo basado en la suma de las ventas realizadas por la combinaci&amp;oacute;n de las dos columnas.&lt;/p&gt;
&lt;p&gt;Si con ADDCOLUMNS intent&amp;aacute;ramos ejecutar una consulta como la siguiente se producir&amp;iacute;a un error, ya que de los par&amp;aacute;metros admitidos por esta funci&amp;oacute;n, s&amp;oacute;lo el primero puede ser una tabla o expresi&amp;oacute;n de tabla, siendo el resto expresiones que generan columnas calculadas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot;, CALCULATE(SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])) &lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;GENERATE. Enriqueciendo el resultado mediante la combinaci&amp;oacute;n de tablas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para resolver este problema recurriremos a la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/gg492196.aspx"&gt;GENERATE&lt;/a&gt;, que recibe como par&amp;aacute;metro dos tablas o expresiones de tabla, generando como resultado el producto cartesiano de ambas. A continuaci&amp;oacute;n vemos una consulta de ejemplo que emplea esta funci&amp;oacute;n para combinar las tablas DimStore y DimGeography.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;GENERATE(&amp;#39;DimStore&amp;#39;,&amp;#39;DimGeography&amp;#39;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Observando el resultado, apreciaremos ocurrencias de filas en la tabla DimStore que tienen una correspondencia geogr&amp;aacute;fica incorrecta al combinarse con la tabla DimGeography, debido precisamente al modo en el que se realiza el cruce entre los registros de ambas tablas. En breve explicaremos c&amp;oacute;mo arreglar este aspecto en particular.&lt;/p&gt;
&lt;p&gt;La forma de aplicar GENERATE para resolver nuestro problema consiste en pasarle como primer par&amp;aacute;metro la funci&amp;oacute;n VALUES, creando as&amp;iacute; la columna con las marcas de productos; y como segundo par&amp;aacute;metro la funci&amp;oacute;n ADDCOLUMNS, para crear tanto la columna de a&amp;ntilde;os como la columna calculada con la suma de ventas. Todo ello lo vemos en la siguiente consulta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;GENERATE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot;, SUMX(RELATEDTABLE(&amp;#39;FactSales&amp;#39;), &amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;)&lt;br /&gt;ORDER BY [BrandName], [CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el conjunto de resultados obtenido, como ya hemos mencionado, habr&amp;aacute; filas con el valor de la columna &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot; vac&amp;iacute;as, que corresponder&amp;aacute;n a registros de la tabla FactSales para los que no se han producido ventas en la fecha con la que se est&amp;aacute;n cruzando.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_11.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para evitar la visualizaci&amp;oacute;n de las filas que no tienen valor en la columna de importe de venta agregaremos a la consulta la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634966.aspx"&gt;FILTER&lt;/a&gt;, en la que situaremos como primer par&amp;aacute;metro la expresi&amp;oacute;n anterior, mientras que en el segundo par&amp;aacute;metro escribiremos una expresi&amp;oacute;n que act&amp;uacute;e como filtro, eliminando las filas sin valor de venta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GENERATE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot;, SUMX(RELATEDTABLE(&amp;#39;FactSales&amp;#39;), &amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NOT(ISBLANK([Ventas por marca y a&amp;ntilde;o]))&lt;br /&gt;)&lt;br /&gt;ORDER BY [BrandName], [CalendarYear]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Otra variante de la expresi&amp;oacute;n de filtro podr&amp;iacute;a ser la siguiente:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;[Ventas por marca y a&amp;ntilde;o] &amp;gt; 0&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Con cualquiera de estas formas de aplicar el filtro, el conjunto de resultados ya no mostrar&amp;aacute; importes vac&amp;iacute;os.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_12.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Con Transact-SQL podemos obtener este mismo resultado utilizando una sentencia muy similar a la &amp;uacute;ltima empleada, pero a&amp;ntilde;adiendo la combinaci&amp;oacute;n con la tabla DimDate y su campo DateKey, as&amp;iacute; como el campo CalendarYear en la cl&amp;aacute;usula GROUP BY.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;WITH tblFactSales AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT DateKey, ProductKey, SalesAmount&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM FactSales&lt;br /&gt;)&lt;br /&gt;SELECT BrandName, CalendarYear, SUM(tblFactSales.SalesAmount) AS [Ventas por marca y a&amp;ntilde;o]&lt;br /&gt;FROM DimProduct&lt;br /&gt;INNER JOIN tblFactSales&lt;br /&gt;ON DimProduct.ProductKey = tblFactSales.ProductKey&lt;br /&gt;INNER JOIN DimDate&lt;br /&gt;ON DimDate.Datekey = tblFactSales.DateKey&lt;br /&gt;GROUP BY BrandName, CalendarYear&lt;br /&gt;ORDER BY BrandName, CalendarYear&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Correcci&amp;oacute;n de efectos no deseados en la ordenaci&amp;oacute;n de n&amp;uacute;meros con formato&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si en la anterior consulta DAX aplicamos un formato (moneda, separador de millar, etc.) sobre la columna &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot;, creada din&amp;aacute;micamente, y ordenamos por dicha columna de la siguiente manera.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GENERATE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot;, FORMAT(SUMX(RELATEDTABLE(&amp;#39;FactSales&amp;#39;), &amp;#39;FactSales&amp;#39;[SalesAmount]), &amp;quot;Currency&amp;quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LEN([Ventas por marca y a&amp;ntilde;o]) &amp;gt; 0&lt;br /&gt;)&lt;br /&gt;ORDER BY [Ventas por marca y a&amp;ntilde;o]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El resultado no se mostrar&amp;aacute; ordenado tal y como esperamos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_13.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esto es debido a que la columna &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot;, por causa del formateo aplicado, contiene datos de tipo car&amp;aacute;cter en lugar de num&amp;eacute;ricos, lo que produce el aparentemente extra&amp;ntilde;o comportamiento en la ordenaci&amp;oacute;n, que en realidad no es tal, ya que se trata del modo correcto de ordenar una columna de tipo string (obs&amp;eacute;rvese tambi&amp;eacute;n que para la condici&amp;oacute;n de filtro hemos utilizado la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634917.aspx"&gt;LEN&lt;/a&gt;, que se emplea en el manejo de cadenas).&lt;/p&gt;
&lt;p&gt;Vamos a solucionar este inconveniente recurriendo de nuevo a la creaci&amp;oacute;n de medidas mediante la instrucci&amp;oacute;n DEFINE, con la que crearemos la medida que realiza la suma de las ventas, la cual emplearemos en los siguientes puntos de la consulta: dentro de ADDCOLUMNS, como expresi&amp;oacute;n de filtro, y como criterio de ordenaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DEFINE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;MEASURE &amp;#39;FactSales&amp;#39;[Ventas] = SUMX(RELATEDTABLE(&amp;#39;FactSales&amp;#39;), &amp;#39;FactSales&amp;#39;[SalesAmount])&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;FILTER(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GENERATE(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimDate&amp;#39;[CalendarYear]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca y a&amp;ntilde;o&amp;quot;, FORMAT(&amp;#39;FactSales&amp;#39;[Ventas], &amp;quot;Currency&amp;quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [Ventas] &amp;gt; 0&lt;br /&gt;)&lt;br /&gt;ORDER BY [Ventas] DESC&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_14.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La obtenci&amp;oacute;n de resultados procedentes de dos tablas resulta una estupenda posibilidad de la que disponemos al escribir consultas DAX, aunque en escenarios en los que debamos manejar informaci&amp;oacute;n de un mayor n&amp;uacute;mero de tablas resultar&amp;aacute; insuficiente. En la siguiente parte de esta serie abordaremos dicha cuesti&amp;oacute;n.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=208887" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>La función VALUES y la creación de medidas calculadas. Profundizando en el uso de DAX como lenguaje de consulta (2)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/03/12/la-funci-243-n-values-y-la-creaci-243-n-de-medidas-calculadas-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-2.aspx</link><pubDate>Tue, 12 Mar 2013 08:59:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:208840</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=208840</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=208840</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/03/12/la-funci-243-n-values-y-la-creaci-243-n-de-medidas-calculadas-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-2.aspx#comments</comments><description>&lt;p&gt;En la primera parte de esta serie comenzamos abordando la creaci&amp;oacute;n de columnas calculadas, que un&amp;iacute;amos al resto de columnas de la tabla mediante la funci&amp;oacute;n ADDCOLUMNS. En esta segunda entrega veremos c&amp;oacute;mo construir consultas basadas en los valores de una &amp;uacute;nica columna.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;VALUES. Valores distintos de una columna&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Aunque la funci&amp;oacute;n ADDCOLUMNS es adecuada para dotar de valores adicionales a una tabla, puede suceder que en determinados momentos estemos m&amp;aacute;s interesados en obtener el contenido de una sola de sus columnas, y m&amp;aacute;s concretamente, de los distintos valores que la componen, bien para visualizarlos o como parte de una expresi&amp;oacute;n m&amp;aacute;s compleja.&lt;/p&gt;
&lt;p&gt;Para tal cometido disponemos de la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634547.aspx"&gt;VALUES&lt;/a&gt;, que recibe como par&amp;aacute;metro una columna de la que extrae sus distintos valores, retorn&amp;aacute;ndolos en forma de tabla de una sola columna, como vemos en el siguiente ejemplo, donde se muestran los nombres de las marcas de productos de la tabla DimProduct.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;VALUES(&amp;#39;DimProduct&amp;#39;[BrandName])&lt;br /&gt;ORDER BY [BrandName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En una consulta SQL disponemos de la cl&amp;aacute;usula DISTINCT, con la que obtendremos los distintos valores de uno de los campos de la tabla.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT DISTINCT BrandName &lt;br /&gt;FROM DimProduct &lt;br /&gt;ORDER BY BrandName&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Puesto que el tipo de dato devuelto por VALUES es una tabla, y ADDCOLUMNS recibe un valor de este tipo en su primer par&amp;aacute;metro, podemos combinar ambas funciones para crear una consulta en la que mostremos las marcas de productos de la tabla DimProduct, y una columna calculada que sume las ventas de la tabla FactSales, obteniendo como resultado las cifras de ventas por cada marca. Recordemos que para que la operaci&amp;oacute;n de suma se lleve a cabo correctamente emplearemos las funciones CALCULATE y SUM, o la combinaci&amp;oacute;n de SUMX y RELATEDTABLE.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca&amp;quot;, CALCULATE(SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]))&lt;br /&gt;)&lt;br /&gt;ORDER BY [BrandName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_09.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634943.aspx"&gt;DISTINCT&lt;/a&gt; tambi&amp;eacute;n devuelve, al igual que VALUES, los valores &amp;uacute;nicos de una columna, por lo que en la mayor&amp;iacute;a de las situaciones los resultados ser&amp;aacute;n iguales utilizando indistintamente una u otra. No obstante, en algunos casos, VALUES devolver&amp;aacute; un valor vac&amp;iacute;o o elemento desconocido, cuando al combinar dos tablas no exista correspondencia entre alguno de sus miembros.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DISTINCT(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca&amp;quot;, CALCULATE(SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]))&lt;br /&gt;)&lt;br /&gt;ORDER BY [BrandName]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Desde Transact-SQL necesitamos en este caso emplear la cl&amp;aacute;usula GROUP BY, puesto que junto al campo BrandName vamos a usar la funci&amp;oacute;n de agregado SUM. Para la combinaci&amp;oacute;n entre las tablas DimProduct y FactSales definiremos sobre esta &amp;uacute;ltima una expresi&amp;oacute;n com&amp;uacute;n de tabla o CTE (Common Table Expression). &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;WITH tblFactSales AS&lt;br /&gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT ProductKey, SalesAmount&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM FactSales&lt;br /&gt;)&lt;br /&gt;SELECT BrandName, SUM(tblFactSales.SalesAmount) AS [Ventas por marca]&lt;br /&gt;FROM DimProduct&lt;br /&gt;INNER JOIN tblFactSales&lt;br /&gt;ON DimProduct.ProductKey = tblFactSales.ProductKey&lt;br /&gt;GROUP BY BrandName&lt;br /&gt;ORDER BY BrandName&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;DEFINE y MEASURE.&lt;/b&gt;&lt;b&gt; Creaci&amp;oacute;n y&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;reutilizaci&amp;oacute;n de medidas calculadas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si en la anterior consulta con VALUES quisi&amp;eacute;ramos adem&amp;aacute;s ordenar el resultado por la columna &amp;quot;Ventas por marca&amp;quot;, tendr&amp;iacute;amos que repetir la expresi&amp;oacute;n que contiene la operaci&amp;oacute;n de suma en la cl&amp;aacute;usula de ordenaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca&amp;quot;, CALCULATE(SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])) &lt;br /&gt;)&lt;br /&gt;ORDER BY CALCULATE(SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]))&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta situaci&amp;oacute;n puede resultar bastante inc&amp;oacute;moda en el caso de consultas extensas, provocando adem&amp;aacute;s, que nuestro c&amp;oacute;digo se vuelva m&amp;aacute;s complicado de leer y mantener.&amp;nbsp;&amp;nbsp; &lt;/p&gt;
&lt;p&gt;Una forma de evitar este tipo de reiteraciones pasa por utilizar las instrucciones &lt;a href="http://technet.microsoft.com/en-us/library/gg492156.aspx"&gt;DEFINE&lt;/a&gt; y &lt;a href="http://technet.microsoft.com/en-us/library/gg492156.aspx"&gt;MEASURE&lt;/a&gt; al comienzo de la consulta, las cuales, tal y como sus nombres indican, nos permiten definir una medida calculada que podemos reutilizar tantas veces como queramos a lo largo de la consulta. Como ventaja adicional, en el ejemplo que nos ocupa, al crear la medida con DEFINE ya no ser&amp;aacute; necesario emplear la funci&amp;oacute;n CALCULATE.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DEFINE&lt;br /&gt;MEASURE FactSales[Ventas] = SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;&lt;br /&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VALUES(&amp;#39;DimProduct&amp;#39;[BrandName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas por marca&amp;quot;, FORMAT(FactSales[Ventas], &amp;quot;Currency&amp;quot;)&lt;br /&gt;)&lt;br /&gt;ORDER BY FactSales[Ventas] DESC&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para mejorar la visualizaci&amp;oacute;n de los datos al crear esta nueva versi&amp;oacute;n de la consulta incluimos la funci&amp;oacute;n FORMAT, aplicando un formato de moneda a la medida/columna calculada.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_10.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El siguiente paso consistir&amp;aacute; en construir una consulta compuesta por columnas provenientes de varias tablas, cuesti&amp;oacute;n esta que abordaremos en las pr&amp;oacute;ximas entregas.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=208840" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>La función ADDCOLUMNS. Profundizando en el uso de DAX como lenguaje de consulta (1)</title><link>http://geeks.ms/blogs/lmblanco/archive/2013/03/04/la-funci-243-n-addcolumns-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-1.aspx</link><pubDate>Mon, 04 Mar 2013 19:56:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:208767</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=208767</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=208767</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2013/03/04/la-funci-243-n-addcolumns-profundizando-en-el-uso-de-dax-como-lenguaje-de-consulta-1.aspx#comments</comments><description>&lt;p&gt;Como ya explic&amp;aacute;bamos en el art&amp;iacute;culo sobre creaci&amp;oacute;n de consultas para modelos tabulares (&lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/11/06/creaci-243-n-de-consultas-para-modelos-tabulares-en-sql-server-2012-1.aspx"&gt;primera&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/11/08/creaci-243-n-de-consultas-para-modelos-tabulares-en-sql-server-2012-y-2.aspx"&gt;segunda&lt;/a&gt; parte), el lenguaje DAX puede ser utilizado para emitir consultas contra un modelo tabular, obteniendo como respuesta un conjunto de resultados, dentro de una mec&amp;aacute;nica similar a la que estamos acostumbrados a emplear cuando trabajamos con el motor relacional, es decir, mediante sentencias SQL del estilo &amp;quot;SELECT ListaDeCampos FROM Tabla&amp;quot;. Esta funcionalidad del lenguaje recibe el nombre de &lt;i&gt;Consultas DAX&lt;/i&gt; (DAX Queries), siendo la instrucci&amp;oacute;n EVALUATE la encargada de llevarla a cabo empleando sentencias del tipo &amp;quot;EVALUATE Expresi&amp;oacute;n&amp;quot;.&lt;/p&gt;
&lt;p&gt;Aunque inicialmente, las consultas DAX no estaban disponibles en el lenguaje cuando PowerPivot hizo su primera presentaci&amp;oacute;n, la llegada de SQL Server 2012, que posiciona a Business Intelligence Semantic Model (BISM) como el nuevo paradigma en el desarrollo de soluciones de inteligencia de negocio, ha supuesto una ampliaci&amp;oacute;n de las caracter&amp;iacute;sticas del lenguaje, que ahora nos va a permitir escribir consultas contra los nuevos modelos tabulares pertenecientes a BISM.&lt;/p&gt;
&lt;p&gt;Con el presente art&amp;iacute;culo iniciamos una serie en la que continuaremos la l&amp;iacute;nea de exploraci&amp;oacute;n iniciada en el art&amp;iacute;culo antes mencionado, por lo que son recomendables, al menos, unos conocimientos b&amp;aacute;sicos sobre DAX, de forma que los ejemplos que vamos a exponer puedan ser seguidos adecuadamente. Adicionalmente, en aquellos casos en que se estime oportuno, mostraremos el c&amp;oacute;digo de la consulta tanto en lenguaje DAX como en Transact-SQL, lo que nos permitir&amp;aacute; observar las diferencias entre ambos a la hora de abordar la resoluci&amp;oacute;n de un mismo problema.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;El proyecto de ejemplo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Como base de los ejemplos que iremos desarrollando vamos a utilizar el modelo ContosoTabular, anteriormente creado &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/11/06/creaci-243-n-de-consultas-para-modelos-tabulares-en-sql-server-2012-1.aspx"&gt;aqu&amp;iacute;&lt;/a&gt;; aunque en esta ocasi&amp;oacute;n volveremos a abrir el proyecto de dicho modelo en SQL Server Data Tools (SSDT) para a&amp;ntilde;adir la tabla DimEmployee (necesaria en alguna de las diversas pruebas a realizar), tras lo cual desplegaremos nuevamente el modelo en el servidor de an&amp;aacute;lisis de SQL Server, actualizando as&amp;iacute; los cambios realizados. A continuaci&amp;oacute;n ejecutaremos SQL Server Management Studio (SSMS) abriendo una ventana de consulta, que a partir de este momento utilizaremos para ilustrar las funciones empleadas en la construcci&amp;oacute;n de consultas DAX.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ADDCOLUMNS. Creaci&amp;oacute;n din&amp;aacute;mica de columnas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/gg492204.aspx"&gt;ADDCOLUMNS&lt;/a&gt; permite crear una o varias columnas calculadas a partir de una tabla o expresi&amp;oacute;n de tabla. Como primer par&amp;aacute;metro situaremos la tabla a la que se a&amp;ntilde;adir&amp;aacute; la columna(s), definiendo a continuaci&amp;oacute;n cada una de las columnas mediante una cadena para el t&amp;iacute;tulo y una expresi&amp;oacute;n DAX con la f&amp;oacute;rmula para el c&amp;aacute;lculo de la columna.&lt;/p&gt;
&lt;p&gt;En la siguiente sentencia mostramos la tabla DimStore junto a una columna calculada que duplica el n&amp;uacute;mero de empleados de cada almac&amp;eacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Empleados Duplicados&amp;quot;, [EmployeeCount] * 2&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para obtener el mismo resultado utilizando la instrucci&amp;oacute;n SELECT en Transact-SQL escribiremos la siguiente consulta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT *, EmployeeCount * 2 AS [Empleados Duplicados]&lt;br /&gt;FROM DimStore&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Continuando con la tabla DimStore, supongamos que de la columna OpenDate, que contiene la fecha de apertura del almac&amp;eacute;n, queremos obtener la parte correspondiente al mes como nombre. Una posibilidad, aunque no la m&amp;aacute;s &amp;oacute;ptima, como veremos enseguida, ser&amp;iacute;a utilizar la siguiente consulta, en la que combinando ADDCOLUMNS con las funciones &lt;a href="http://technet.microsoft.com/en-us/library/ee634914.aspx"&gt;MONTH&lt;/a&gt; y &lt;a href="http://technet.microsoft.com/en-us/library/gg492166.aspx"&gt;SWITCH&lt;/a&gt;, obtenemos una nueva columna con el nombre del mes correspondiente a OpenDate.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Mes Apertura&amp;quot;, SWITCH(MONTH([OpenDate]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1,&amp;quot;Enero&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2,&amp;quot;Febrero&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3,&amp;quot;Marzo&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4,&amp;quot;Abril&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5,&amp;quot;Mayo&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6,&amp;quot;Junio&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7,&amp;quot;Julio&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8,&amp;quot;Agosto&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 9,&amp;quot;Septiembre&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 10,&amp;quot;Octubre&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 11,&amp;quot;Noviembre&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 12,&amp;quot;Diciembre&amp;quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n MONTH devuelve el n&amp;uacute;mero del mes de la fecha pasada como par&amp;aacute;metro. Si este resultado lo pasamos a su vez como par&amp;aacute;metro a la funci&amp;oacute;n SWITCH, para cada n&amp;uacute;mero retornamos una cadena con el nombre del mes correspondiente. &lt;/p&gt;
&lt;p&gt;Pero como ya dec&amp;iacute;amos antes, existe una forma mucho m&amp;aacute;s simple de obtener el mismo resultado, consistente en utilizar la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634924.aspx"&gt;FORMAT&lt;/a&gt;, a la que pasaremos como primer par&amp;aacute;metro la columna de fecha, y como segundo la cadena con el formato que deseamos aplicar. La siguiente expresi&amp;oacute;n consigue el mismo resultado que la anterior pero con mucho menos c&amp;oacute;digo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Mes Apertura&amp;quot;, FORMAT([OpenDate], &amp;quot;MMMM&amp;quot;)&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En Transact-SQL tambi&amp;eacute;n disponemos de la funci&amp;oacute;n FORMAT que se utiliza como vemos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SET LANGUAGE Spanish&lt;/p&gt;
&lt;p&gt;SELECT *, FORMAT(OpenDate, &amp;#39;MMMM&amp;#39;) AS [Mes Apertura]&lt;br /&gt;FROM DimStore&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Compliquemos ahora un poco la expresi&amp;oacute;n utilizada para crear la columna calculada: supongamos que necesitamos averiguar la cantidad de a&amp;ntilde;os transcurridos desde la fecha de apertura del almac&amp;eacute;n (columna OpenDate) hasta la fecha actual, teniendo en cuenta que si existe valor en la columna CloseDate significar&amp;aacute; que el almac&amp;eacute;n ya ha sido cerrado.&lt;/p&gt;
&lt;p&gt;La expresi&amp;oacute;n de columna para resolver esta situaci&amp;oacute;n implicar&amp;aacute;, pues, el uso de las siguientes funciones: &lt;a href="http://technet.microsoft.com/en-us/library/ee634567.aspx"&gt;YEAR&lt;/a&gt;, para extraer el a&amp;ntilde;o de las columnas de fecha; &lt;a href="http://technet.microsoft.com/en-us/library/ee634891.aspx"&gt;NOW&lt;/a&gt;, para obtener la fecha actual; &lt;a href="http://technet.microsoft.com/en-us/library/ee634204.aspx"&gt;ISBLANK&lt;/a&gt;, para comprobar la existencia de valor en la columna CloseDate; e &lt;a href="http://technet.microsoft.com/en-us/library/ee634824.aspx"&gt;IF&lt;/a&gt;, para determinar la operaci&amp;oacute;n que realiza el c&amp;aacute;lculo de a&amp;ntilde;os seg&amp;uacute;n la columna CloseDate tenga o no valor.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;A&amp;ntilde;os actividad almac&amp;eacute;n&amp;quot;, IF(ISBLANK([CloseDate]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; YEAR(NOW()) - YEAR([OpenDate]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; YEAR([CloseDate]) - YEAR([OpenDate])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En SQL usaremos la funci&amp;oacute;n DATEDIFF para hallar la diferencia entre las fechas. La expresi&amp;oacute;n CASE nos servir&amp;aacute; para utilizar en el c&amp;aacute;lculo la fecha actual o la de cierre del almac&amp;eacute;n si la primera es nula.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT *,&lt;br /&gt;CASE&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHEN CloseDate IS NULL THEN&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DATEDIFF(year, OpenDate, GETDATE())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DATEDIFF(year, OpenDate, CloseDate) &lt;br /&gt;END AS [A&amp;ntilde;os actividad almac&amp;eacute;n]&lt;br /&gt;FROM DimStore&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Las columnas calculadas creadas hasta el momento con la funci&amp;oacute;n ADDCOLUMNS se basan en operaciones sobre las columnas de la propia tabla DimStore, pasada como primer par&amp;aacute;metro a la funci&amp;oacute;n. No obstante, tambi&amp;eacute;n es posible generar columnas din&amp;aacute;micas que pertenezcan a otras tablas del modelo tabular con las que DimStore guarda relaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Observando el diagrama de tablas del modelo tabular en SSDT, vemos que DimStore mantiene relaciones con las tablas FactSales, DimGeography y DimEmployee.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Es por lo tanto perfectamente posible crear una columna calculada con ADDCOLUMNS que muestre la informaci&amp;oacute;n de la columna RegionCountryName, perteneciente a la tabla DimGeography, ya que se relaciona con la tabla DimStore a trav&amp;eacute;s de la columna GeographyKey, com&amp;uacute;n en ambas tablas. Es necesario tener en cuenta que en el momento de crear la expresi&amp;oacute;n de la columna calculada debemos indicar expl&amp;iacute;citamente la existencia de dicha relaci&amp;oacute;n utilizando la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634202.aspx"&gt;RELATED&lt;/a&gt;. Esta nueva columna tendr&amp;aacute; como t&amp;iacute;tulo &amp;quot;Pa&amp;iacute;s ubicaci&amp;oacute;n&amp;quot;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Pa&amp;iacute;s ubicaci&amp;oacute;n&amp;quot;, RELATED(&amp;#39;DimGeography&amp;#39;[RegionCountryName])&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Adem&amp;aacute;s, tal y como explic&amp;aacute;bamos al principio de este apartado, con ADDCOLUMNS podemos crear varias columnas calculadas al mismo tiempo, por lo que a&amp;ntilde;adiremos a la consulta anterior otra expresi&amp;oacute;n con el t&amp;iacute;tulo &amp;quot;Ventas almac&amp;eacute;n&amp;quot;, que realice, empleando la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634387.aspx"&gt;SUM&lt;/a&gt;, la suma de la columna SalesAmount, perteneciente a la tabla FactSales, con la que tambi&amp;eacute;n se relaciona DimStore a trav&amp;eacute;s del campo StoreKey.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Pa&amp;iacute;s ubicaci&amp;oacute;n&amp;quot;, RELATED(&amp;#39;DimGeography&amp;#39;[RegionCountryName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas almac&amp;eacute;n&amp;quot;, SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Pero observando el resultado obtenido vemos que hay algo que no funciona correctamente, ya que la finalidad de la anterior consulta consiste en obtener la suma del campo SalesAmount para cada uno de los almacenes, y lo que hemos conseguido es que el valor de la columna calculada &amp;quot;Ventas almac&amp;eacute;n&amp;quot; muestre en todos los casos la suma total de SalesAmount, lo cual no es el objetivo que perseguimos.&lt;/p&gt;
&lt;p&gt;Podemos solucionar este problema de dos formas: la primera consiste en sustituir la funci&amp;oacute;n SUM por &lt;a href="http://technet.microsoft.com/en-us/library/ee634959.aspx"&gt;SUMX&lt;/a&gt;, que sobre una tabla pasada como primer par&amp;aacute;metro realiza la suma de la columna pasada en el segundo par&amp;aacute;metro. Aqu&amp;iacute; tambi&amp;eacute;n debemos indicar que existe una relaci&amp;oacute;n entre DimStore y FactSales, para lo que usaremos la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634226.aspx"&gt;RELATEDTABLE&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Pa&amp;iacute;s ubicaci&amp;oacute;n&amp;quot;, RELATED(&amp;#39;DimGeography&amp;#39;[RegionCountryName]),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas almac&amp;eacute;n&amp;quot;, SUMX(RELATEDTABLE(&amp;#39;FactSales&amp;#39;), &amp;#39;FactSales&amp;#39;[SalesAmount])&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma la suma ya se realizar&amp;aacute; de forma separada para cada almac&amp;eacute;n.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201303/ProfundizandoUsoDAXComoLenguajeConsulta_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La otra v&amp;iacute;a de abordar la suma de las ventas por almac&amp;eacute;n consiste en utilizar la funci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/ee634825.aspx"&gt;CALCULATE&lt;/a&gt;, a la que pasaremos como par&amp;aacute;metro la operaci&amp;oacute;n de suma. CALCULATE se encargar&amp;aacute; de evaluar dicha expresi&amp;oacute;n para cada uno de los almacenes (valores distintos del campo StoreKey) existentes en la tabla DimStore, obteniendo de esta manera el resultado deseado.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE&lt;br /&gt;ADDCOLUMNS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;#39;DimStore&amp;#39;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Pa&amp;iacute;s ubicaci&amp;oacute;n&amp;quot;, RELATED(&amp;#39;DimGeography&amp;#39;[RegionCountryName]),&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;Ventas almac&amp;eacute;n&amp;quot;, CALCULATE(SUM(&amp;#39;FactSales&amp;#39;[SalesAmount]))&lt;br /&gt;)&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n CALCULATE puede revestir cierta complejidad inicial, por lo que recomendamos visitar el siguiente &lt;a href="http://sqlblog.com/blogs/marco_russo/archive/2010/01/03/how-calculate-works-in-dax.aspx"&gt;post&lt;/a&gt; del blog de Marco Russo, en el que realiza una detallada explicaci&amp;oacute;n acerca de su funcionamiento.&lt;/p&gt;
&lt;p&gt;Para obtener este resultado con Transact-SQL usaremos una combinaci&amp;oacute;n de tipo LEFT JOIN entre las tablas DimStore y DimGeography, adem&amp;aacute;s de una subconsulta sobre la tabla FactSales, que realice la suma del campo SalesAmount con la funci&amp;oacute;n SUM.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT S.*, G.RegionCountryName,&lt;br /&gt;(SELECT SUM(F.SalesAmount) FROM FactSales AS F WHERE F.StoreKey = S.StoreKey) AS [Ventas almac&amp;eacute;n]&lt;br /&gt;FROM DimStore AS S&lt;br /&gt;LEFT JOIN DimGeography AS G&lt;br /&gt;ON S.GeographyKey = G.GeographyKey&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como hemos podido comprobar, la funci&amp;oacute;n ADDCOLUMNS resulta de gran utilidad a la hora de a&amp;ntilde;adir a nuestras consultas informaci&amp;oacute;n adicional en forma de columnas calculadas. En las siguientes entregas explicaremos diversas t&amp;eacute;cnicas y funciones del lenguaje, mediante las que conseguiremos seleccionar un subconjunto de columnas de la tabla, evitando la necesidad de obtener la totalidad de las mismas.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=208767" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Mostrar el escritorio en Windows 8</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/11/11/mostrar-el-escritorio-en-windows-8.aspx</link><pubDate>Sun, 11 Nov 2012 21:50:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207382</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=207382</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=207382</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/11/11/mostrar-el-escritorio-en-windows-8.aspx#comments</comments><description>&lt;p&gt;Una de las primeras cosas que busqu&amp;eacute; en el modo de escritorio tradicional al instalar el nuevo Windows 8 fue el bot&amp;oacute;n &amp;quot;Mostrar escritorio&amp;quot;. Se trata de una opci&amp;oacute;n que particularmente considero muy &amp;uacute;til y c&amp;oacute;moda para limpiar el escritorio cuando est&amp;aacute; plagado de ventanas. Sin embargo, en un principio s&amp;oacute;lo encontr&amp;eacute; esta posibilidad haciendo clic derecho en la barra de tareas.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/MostrarEscritorioWindows8_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tras publicar este post, Ant&amp;oacute;n Molleda (al que agradezco su inter&amp;eacute;s y ayuda) envi&amp;oacute; un acertado comentario indicando que en el extremo derecho de la barra de tareas, si bien no tiene la forma de un bot&amp;oacute;n, podemos seguir haciendo clic, provocando la desaparici&amp;oacute;n de las ventanas actualmente visibles en el escritorio (efecto que tambi&amp;eacute;n conseguiremos con la combinaci&amp;oacute;n de teclas Windows+D).&lt;/p&gt;
&lt;p&gt;Si adem&amp;aacute;s de todo esto queremos contar con la posibilidad de disponer de un acceso directo anclado en la barra de tareas para lograr el mismo resultado, podemos seguir lo sencillos pasos que se comentan a continuaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En primer lugar haremos clic derecho en una zona vac&amp;iacute;a del escritorio, seleccionando la opci&amp;oacute;n &amp;quot;Nuevo | Acceso directo&amp;quot;. En la ventana de creaci&amp;oacute;n del acceso directo que aparecer&amp;aacute; seguidamente, escribiremos la siguiente instrucci&amp;oacute;n en el campo de ubicaci&amp;oacute;n del elemento:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;C:\windows\explorer.exe shell:::{3080F90D-D7AD-11D9-BD98-0000947B0257}&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/MostrarEscritorioWindows8_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el siguiente paso daremos un nombre al acceso directo y haremos clic en Finalizar para completar su creaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/MostrarEscritorioWindows8_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El icono del acceso directo reci&amp;eacute;n creado es igual al del Explorador de archivos, por lo que puede resultar una buena idea cambiarlo. Haciendo clic derecho sobre el icono seleccionaremos la opci&amp;oacute;n Propiedades, abri&amp;eacute;ndose una ventana del mismo nombre, en la que haremos clic en el bot&amp;oacute;n &amp;quot;Cambiar icono...&amp;quot;; lo que a su vez abrir&amp;aacute; el cuadro de di&amp;aacute;logo para realizar esta operaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Podemos elegir entre los iconos que acompa&amp;ntilde;an al archivo explorer.exe, ofrecido por defecto, o bien usar alguno de los siguientes archivos, que tambi&amp;eacute;n adjuntan colecciones de iconos.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;%SystemRoot%\system32\Shell32.dll&lt;/p&gt;
&lt;p&gt;%SystemRoot%\system32\imageres.dll&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/MostrarEscritorioWindows8_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Aceptando ambas ventanas confirmaremos el cambio de icono para el acceso directo, por lo que ya podemos hacer doble clic sobre el mismo para ocultar todas las ventanas del escritorio.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/MostrarEscritorioWindows8_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como detalle final podemos hacer clic derecho en el acceso directo y seleccionar la opci&amp;oacute;n &amp;quot;Anclar a la barra de tareas&amp;quot;, para tener esta opci&amp;oacute;n disponible de forma mucho m&amp;aacute;s inmediata.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/MostrarEscritorioWindows8_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Espero que os resulte de utilidad.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207382" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx">Trucos</category></item><item><title>Creación de consultas para modelos tabulares en SQL Server 2012 (y 2)</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/11/08/creaci-243-n-de-consultas-para-modelos-tabulares-en-sql-server-2012-y-2.aspx</link><pubDate>Thu, 08 Nov 2012 18:02:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207365</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=207365</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=207365</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/11/08/creaci-243-n-de-consultas-para-modelos-tabulares-en-sql-server-2012-y-2.aspx#comments</comments><description>&lt;p&gt;En la primera parte de este art&amp;iacute;culo explic&amp;aacute;bamos la forma de crear un modelo tabular en SQL Server 2012 para su posterior consulta utilizando algunas de las t&amp;eacute;cnicas que ilustraremos en esta segunda entrega.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Consultas DAX&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Todos aquellos lectores que hayan tenido la oportunidad de trabajar con &lt;a href="http://dnmplus.net/articulos/powerpivot-dax-y-excel-business-intelligence-para-todos-los-publicos.aspx"&gt;PowerPivot&lt;/a&gt; conocer&amp;aacute;n en mayor o menor medida el lenguaje DAX y la capacidad que otorga al usuario de construir, en un modelo de datos, expresiones en forma de columnas y medidas calculadas para obtener los resultados anal&amp;iacute;ticos requeridos.&lt;/p&gt;
&lt;p&gt;En lo que respecta al desarrollo de modelos tabulares, a las funcionalidades que acabamos de mencionar se suma ahora la posibilidad de escribir consultas con las que obtener conjuntos de resultados a partir de las tablas del modelo.&lt;/p&gt;
&lt;p&gt;Para ello haremos uso de la instrucci&amp;oacute;n &lt;a href="http://technet.microsoft.com/en-us/library/gg492156.aspx"&gt;EVALUATE&lt;/a&gt; que representa la pieza fundamental en la construcci&amp;oacute;n de consultas DAX contra un modelo tabular, acompa&amp;ntilde;ando a la misma el nombre de la tabla a obtener, tal y como vemos en el siguiente ejemplo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE DimStore;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para poder apreciar el resultado de la ejecuci&amp;oacute;n de esta sentencia iniciaremos SSMS y nos conectaremos a Analysis Server. A continuaci&amp;oacute;n haremos clic en el modelo ContosoTabular reci&amp;eacute;n desplegado en el servidor, que aparece como nodo dependiente de la instancia de Analysis Server, y seleccionaremos la opci&amp;oacute;n de men&amp;uacute; &amp;quot;File | New | Query with Current Connection&amp;quot;, que abrir&amp;aacute; una ventana de consultas MDX que en este caso utilizaremos para escribir sentencias DAX. Antes de proseguir aclararemos al lector que cuando nos encontramos trabajando con modelos tabulares, el editor de consultas de SSMS, a pesar de guardar los archivos de sentencias con la extensi&amp;oacute;n MDX, soporta tanto consultas DAX como MDX.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_13.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si ya hemos consultado la documentaci&amp;oacute;n oficial que sobre la instrucci&amp;oacute;n EVALUATE existe, veremos que es posible ordenar el conjunto de resultados obtenido mediante la cl&amp;aacute;usula ORDER BY, de tal forma que si modificamos nuestra consulta de la manera mostrada en la siguiente sentencia, los datos aparecer&amp;aacute;n ordenados por la columna StoreManager.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE DimStore&lt;br /&gt;ORDER BY [StoreManager];&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Podemos combinar varias columnas a la hora de ordenar, as&amp;iacute; como alterar el sentido de la ordenaci&amp;oacute;n con los modificadores ASC y DESC.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE DimStore&lt;br /&gt;ORDER BY [StoreManager] ASC, [StoreKey] DESC;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_14.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Pero a&amp;uacute;n hay m&amp;aacute;s respecto a la ordenaci&amp;oacute;n, ya que usando la subcl&amp;aacute;usula START AT conseguiremos que los datos comiencen a mostrarse a partir de un determinado valor, perteneciente a la columna(s) que participa en el orden.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;EVALUATE DimStore&lt;br /&gt;ORDER BY [StoreManager] START AT 75;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dedicaremos un pr&amp;oacute;ximo art&amp;iacute;culo a profundizar en el uso de EVALUATE y el resto de instrucciones DAX especialmente desarrolladas para el trabajo con modelos tabulares.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Elementos calculados. Medidas y columnas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En un modelo de datos tabular, adem&amp;aacute;s de la informaci&amp;oacute;n que obtenemos de las columnas de una tabla, podemos encontrarnos con columnas y medidas calculadas que no forman parte de la estructura original de dicha tabla, sino que son producto de una expresi&amp;oacute;n/f&amp;oacute;rmula DAX. En este apartado haremos una primera aproximaci&amp;oacute;n a este tipo de elementos de un modelo.&lt;/p&gt;
&lt;p&gt;Pongamos por ejemplo que para la tabla FactSales queremos saber cu&amp;aacute;nto ha supuesto el total de ventas, por lo que tendremos que aplicar una operaci&amp;oacute;n de suma sobre la columna SalesAmount.&lt;/p&gt;
&lt;p&gt;En primer lugar nos situaremos en dicha tabla dentro del dise&amp;ntilde;ador. Como podemos comprobar, la cuadr&amp;iacute;cula de datos se divide en dos zonas: la superior, correspondiente a los propios registros de la tabla; y la inferior, reservada a las medidas calculadas, y que actualmente se encuentra vac&amp;iacute;a.&lt;/p&gt;
&lt;p&gt;Para crear la medida que sume las filas de la columna SalesAmount haremos clic en una celda vac&amp;iacute;a de la zona inferior de dicha columna, y a continuaci&amp;oacute;n escribiremos la siguiente expresi&amp;oacute;n en la barra de f&amp;oacute;rmulas del dise&amp;ntilde;ador.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;TotalVentas:=SUM([SalesAmount])&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma obtendremos una medida con el nombre TotalVentas, que mostrar&amp;aacute; el resultado de la operaci&amp;oacute;n de suma sobre la columna.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_15.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n conseguiremos el mismo resultado mediante la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Column | AutoSum | Sum&amp;quot;, con la diferencia de que el nombre de la medida (Sum of SalesAmount) ser&amp;aacute; asignado autom&amp;aacute;ticamente, no obstante, siempre podemos recurrir a la ventana de propiedades de la medida y cambiarle el nombre en su propiedad Measure Name.&lt;/p&gt;
&lt;p&gt;Pasemos seguidamente a la creaci&amp;oacute;n de una columna calculada, donde vamos a suponer que necesitamos una nueva columna para la tabla FactSales, en la que se realice una operaci&amp;oacute;n sobre la columna SalesAmount, que arroje como resultado el valor de dicha columna para la fila actual menos el 10%. Esto lo conseguiremos haciendo clic en una celda de la primera columna vac&amp;iacute;a disponible en la tabla y escribiendo la siguiente sentencia en la barra de f&amp;oacute;rmulas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;=[SalesAmount] - ([SalesAmount] * 0,1)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n asignaremos el nombre a esta nueva columna haciendo doble clic en su cabecera y escribiendo el valor VentasConDescuento.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_16.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tras la creaci&amp;oacute;n de estos miembros calculados proseguiremos con otro de los modos de consulta a nuestra disposici&amp;oacute;n: las consultas MDX.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Consultas MDX&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Aunque MDX fue desarrollado como lenguaje de consulta para cubos OLAP (modelos multidimensionales), en SQL Server 2012 ha sido adaptado para poder interaccionar tambi&amp;eacute;n con modelos tabulares, de manera que cuando lo empleamos dentro de este contexto, el nombre del modelo (archivo bim del proyecto en SSDT) representa al cubo de datos, mientras que las tablas identifican a las dimensiones. Las medidas que hayamos calculado en las diferentes tablas quedar&amp;aacute;n agrupadas en un nodo aparte, funcionando como una dimensi&amp;oacute;n especial, lo que vemos al abrir el modelo en SSMS.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_17.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para hacer una consulta MDX contra el modelo emplearemos la instrucci&amp;oacute;n SELECT, donde al&amp;nbsp; igual que si consult&amp;aacute;ramos un cubo OLAP, especificaremos, mediante la cl&amp;aacute;usula ON COLUMNS, la dimensi&amp;oacute;n que ubicaremos en el eje de las columnas, y que en este caso ser&amp;aacute; la medida TotalVentas, ya que como hemos mencionado, las medidas del modelo tambi&amp;eacute;n pueden comportarse como una dimensi&amp;oacute;n al crear la consulta.&lt;/p&gt;
&lt;p&gt;Con la cl&amp;aacute;usula ON ROWS indicamos que la dimensi&amp;oacute;n utilizada para las filas ser&amp;aacute; DimGeography, visualizando el nombre de las provincias o estados de los pa&amp;iacute;ses con la funci&amp;oacute;n Children de MDX aplicada al atributo StateProvinceName.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT&lt;/p&gt;
&lt;p&gt;{[Measures].[TotalVentas]} ON COLUMNS,&lt;/p&gt;
&lt;p&gt;{[DimGeography].[StateProvinceName].Children} ON ROWS&lt;/p&gt;
&lt;p&gt;FROM [Model];&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_18.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Agregando la cl&amp;aacute;usula WHERE a la consulta podremos aplicar filtros al resultado. Por ejemplo, si queremos que las cifras de ventas se circunscriban solamente a las ventas de productos de color azul (tabla DimProduct, atributo ColorName), emplearemos la siguiente consulta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT&lt;/p&gt;
&lt;p&gt;{[Measures].[TotalVentas]} ON COLUMNS,&lt;/p&gt;
&lt;p&gt;{[DimGeography].[RegionCountryName].Children} ON ROWS&lt;/p&gt;
&lt;p&gt;FROM [Model]&lt;/p&gt;
&lt;p&gt;WHERE ([DimProduct].[ColorName].&amp;amp;[Azul]);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_19.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Podemos desplazar la medida TotalVentas a la cl&amp;aacute;usula WHERE y poner en las columnas una selecci&amp;oacute;n de los a&amp;ntilde;os en los que se realizaron las ventas. Para especificar dichos a&amp;ntilde;os como un rango, simplemente hemos de poner el primer y &amp;uacute;ltimo elemento del mismo separados por dos puntos, tal y como vemos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT&lt;/p&gt;
&lt;p&gt;{[DimDate].[CalendarYear].&amp;amp;[2007] : [DimDate].[CalendarYear].&amp;amp;[2010]} ON COLUMNS,&lt;/p&gt;
&lt;p&gt;{[DimGeography].[RegionCountryName].Children} ON ROWS&lt;/p&gt;
&lt;p&gt;FROM [Model]&lt;/p&gt;
&lt;p&gt;WHERE ([Measures].[TotalVentas]);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_20.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Excel como herramienta de consulta&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Y llegamos a Excel, el tercero de los tipos de consulta contra modelos tabulares que estamos presentando en este art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;Cuenta como gran ventaja con una potente interfaz de usuario, lo que nos permite construir informes de gran riqueza ya que pone a nuestra&amp;nbsp; disposici&amp;oacute;n un amplio abanico de elementos visuales tales como tablas din&amp;aacute;micas, gr&amp;aacute;ficos, estilos, formatos, etc.&lt;/p&gt;
&lt;p&gt;Una vez iniciado Excel, para acceder al contenido de un modelo tabular haremos clic en la pesta&amp;ntilde;a Datos de la cinta de opciones, y a continuaci&amp;oacute;n, dentro del grupo &amp;quot;Obtener datos externos&amp;quot;, haremos clic en la opci&amp;oacute;n &amp;quot;De otras fuentes&amp;quot; seleccionando en la lista desplegable el valor &amp;quot;Desde Analysis Services&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_21.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como resultado se abrir&amp;aacute; un asistente en el que especificaremos el servidor\instancia a la que queremos conectarnos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_22.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el siguiente paso seleccionaremos la base de datos que contiene el modelo tabular (ContosoTabular) junto al propio modelo, que en el asistente estar&amp;aacute; identificado como un cubo.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_23.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el &amp;uacute;ltimo paso guardamos la informaci&amp;oacute;n de conexi&amp;oacute;n en un archivo.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_24.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como resultado de la ejecuci&amp;oacute;n del asistente se establecer&amp;aacute; una conexi&amp;oacute;n contra el modelo tabular, y en la hoja de c&amp;aacute;lculo se crear&amp;aacute; una tabla din&amp;aacute;mica que nos servir&amp;aacute; como veh&amp;iacute;culo para presentar los datos del modelo. En el panel de campos de la tabla din&amp;aacute;mica tendremos a nuestra disposici&amp;oacute;n las tablas y medidas que hayamos definido en el modelo, que arrastraremos, bien directamente a la&lt;a name="mk2"&gt;&lt;/a&gt; tabla o a los bloques denominados Valores, Etiquetas de fila/columna y Filtro de informe, hasta componer un informe similar al que podemos ver a continuaci&amp;oacute;n, donde analizamos las ventas de productos de color azul en funci&amp;oacute;n de los a&amp;ntilde;os y el pa&amp;iacute;s en que se ha producido la venta.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_25.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Adem&amp;aacute;s podemos a&amp;ntilde;adir un gr&amp;aacute;fico sincronizado con los valores num&amp;eacute;ricos desde la opci&amp;oacute;n Gr&amp;aacute;fico din&amp;aacute;mico, perteneciente a la pesta&amp;ntilde;a Opciones de la pesta&amp;ntilde;a de nivel superior Herramientas de tabla din&amp;aacute;mica. En dicho gr&amp;aacute;fico tambi&amp;eacute;n es posible aplicar filtros al igual que desde la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_26.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Y llegados a este punto damos por concluida esta introducci&amp;oacute;n dedicada a la elaboraci&amp;oacute;n de consultas contra los nuevos modelos tabulares de SQL Server 2012, espero que resulte de ayuda a todos los que quieran empezar a dar sus primeros pasos con esta interesante tecnolog&amp;iacute;a.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207365" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Creación de consultas para modelos tabulares en SQL Server 2012 (1)</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/11/06/creaci-243-n-de-consultas-para-modelos-tabulares-en-sql-server-2012-1.aspx</link><pubDate>Tue, 06 Nov 2012 19:53:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207337</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=207337</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=207337</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/11/06/creaci-243-n-de-consultas-para-modelos-tabulares-en-sql-server-2012-1.aspx#comments</comments><description>&lt;p&gt;Los Servicios de An&amp;aacute;lisis de SQL Server 2012 (SQL Server Analysis Services, SSAS) han experimentado un importante cambio con la introducci&amp;oacute;n del Modelo Sem&amp;aacute;ntico de Inteligencia de Negocio (Business Intelligence Semantic Model, BISM), un nuevo paradigma en la construcci&amp;oacute;n de sistemas anal&amp;iacute;ticos, que a&amp;uacute;na el tradicional modelo multidimensional (Unified Dimensional Model, UDM), propio de los tradicionales cubos OLAP, con el novedoso &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/09/11/sql-server-2012-analysis-services-tabular-models.aspx"&gt;modelo tabular&lt;/a&gt;, basado en un motor de datos relacional, el cual propugna una filosof&amp;iacute;a de trabajo m&amp;aacute;s simple (aunque no menos potente en cuanto al volumen de datos a manejar) que nos permita resolver determinados problemas de una forma m&amp;aacute;s sencilla y &amp;aacute;gil que la requerida habitualmente para desarrollar un modelo multidimensional.&lt;/p&gt;
&lt;p&gt;Y es en estos &amp;uacute;ltimos, los modelos de datos tabulares, sobre los que vamos a concentrar nuestra atenci&amp;oacute;n a lo largo del presente art&amp;iacute;culo, m&amp;aacute;s concretamente en la capacidad de elaborar consultas y m&amp;eacute;tricas contra dichos modelos, las cuales nos permitan recabar la informaci&amp;oacute;n necesaria acerca de su estado.&lt;/p&gt;
&lt;p&gt;Para la confecci&amp;oacute;n de estas consultas emplearemos DAX (Data Analysis eXpressions),&amp;nbsp;el&amp;nbsp;lenguaje desarrollado con el objetivo de crear expresiones anal&amp;iacute;ticas tanto para modelos de datos en PowerPivot como para modelos tabulares en BISM. Tambi&amp;eacute;n usaremos MDX para acceder a una fuente de datos tabular como si de un cubo OLAP se tratara. Finalizaremos nuestro periplo con Excel, como ejemplo de aplicaci&amp;oacute;n de usuario final dotada igualmente de la posibilidad de obtener informaci&amp;oacute;n del modelo, present&amp;aacute;ndola con la conocida potencia gr&amp;aacute;fica de esta herramienta.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creando el modelo tabular&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Lo primero que necesitamos para poner en pr&amp;aacute;ctica lo explicado en el p&amp;aacute;rrafo anterior es un modelo de datos tabular que podamos utilizar como banco de pruebas; as&amp;iacute; que comenzaremos arrancando SQL Server Data Tools (SSDT), el entorno de desarrollo para SQL Server 2012 basado en Visual Studio, que se encuentra en el mismo grupo de programas de SQL Server, y empleando el tipo de proyecto Analysis Services Tabular Project, crearemos un nuevo proyecto con el nombre ContosoTabular que usar&amp;aacute; &lt;a href="http://www.microsoft.com/es-es/download/details.aspx?id=18279"&gt;ContosoRetailDW&lt;/a&gt; como fuente de datos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El siguiente paso que daremos a continuaci&amp;oacute;n consistir&amp;aacute; en la importaci&amp;oacute;n de las tablas de la base de datos ContosoRetailDW, que posteriormente utilizaremos en nuestras operaciones de an&amp;aacute;lisis contra el modelo tabular, por lo que mediante la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Model | Import From Data Source&amp;quot; de SSDT, ejecutaremos el asistente de importaci&amp;oacute;n de datos Table Import Wizard, en cuyo primer paso elegiremos el tipo de origen al que deseamos conectarnos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el siguiente paso introduciremos el servidor e instancia de SQL Server al que nos conectaremos (en este caso EVENDIM como servidor y SQLTABULAR como instancia), as&amp;iacute; como el nombre de la base de datos desde la que importaremos las tablas. Tambi&amp;eacute;n elegiremos Autenticaci&amp;oacute;n de Windows como m&amp;eacute;todo de conexi&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n deberemos facilitar las credenciales de conexi&amp;oacute;n que Analysis Services utilizar&amp;aacute; para conectarse a la base de datos al realizar el proceso de importaci&amp;oacute;n. En este caso emplearemos la cuenta del usuario que ha iniciado sesi&amp;oacute;n en el equipo desde el que se desea conectar, aunque tambi&amp;eacute;n podr&amp;iacute;amos haber usado la cuenta del servicio de Analysis Services, tal y como se explica en el siguiente &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/09/04/configurar-las-credenciales-de-acceso-a-la-fuente-de-datos-en-un-modelo-tabular-de-sql-server-2012.aspx"&gt;enlace&lt;/a&gt; de este mismo blog.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Seguidamente podemos elegir el modo en que se realizar&amp;aacute; la importaci&amp;oacute;n de los datos: mediante una selecci&amp;oacute;n de las tablas/vistas de la base de datos o usando una consulta. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para este ejemplo nos decantaremos por la primera opci&amp;oacute;n, seleccionando las siguientes tablas: DimStore, DimGeography, DimDate, DimProduct, DimProductSubcategory y FactSales.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Completado este paso haremos clic en el bot&amp;oacute;n Finish, que dar&amp;aacute; comienzo al proceso de importaci&amp;oacute;n, a cuyo t&amp;eacute;rmino veremos la ventana de resultados, en la que si todo ha marchado bien, observaremos el detalle de las tablas y registros importados.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez terminado el proceso de importaci&amp;oacute;n, el asistente nos devolver&amp;aacute; a la ventana del dise&amp;ntilde;ador del modelo tabular, donde tendremos a nuestra disposici&amp;oacute;n las tablas reci&amp;eacute;n importadas, organizadas en diversas pesta&amp;ntilde;as.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n es posible visualizar estas tablas en forma de diagrama mediante la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Model | Model View | Diagram View&amp;quot;, lo que nos permitir&amp;aacute; seleccionar la visualizaci&amp;oacute;n de sus columnas, medidas, jerarqu&amp;iacute;as, etc., as&amp;iacute; como las relaciones existentes entre estas.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_09.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para retornar a la anterior vista del dise&amp;ntilde;ador usaremos la opci&amp;oacute;n &amp;quot;Model | Model View | Data View&amp;quot;. &amp;nbsp;Podemos conmutar entre estas dos vistas empleando los botones situados en la parte inferior derecha del dise&amp;ntilde;ador.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_10.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Despliegue del modelo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Finalizada por el momento la etapa de desarrollo del modelo, procederemos a efectuar el despliegue del mismo en el servidor de an&amp;aacute;lisis, de modo que pueda ser consultado por aquellas aplicaciones cliente que lo requieran. Para ello seleccionaremos la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Build | Deploy ContosoTabular&amp;quot; o haremos clic derecho en el icono correspondiente al proyecto en el Explorador de Soluciones, eligiendo la opci&amp;oacute;n Deploy. Ambas acciones conducir&amp;aacute;n a la ventana de despliegue, que nos ir&amp;aacute; informando acerca del progreso de la operaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_11.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si el despliegue se realiza con &amp;eacute;xito, cerraremos su ventana de progreso y abriremos SQL Server Management Studio (SSMS), conect&amp;aacute;ndonos a Analysis Services, donde encontraremos el modelo reci&amp;eacute;n subido al servidor. Expandiendo su nodo principal veremos las tablas que lo componen.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201211/CreacionConsultasModelosTabularesSQL2012_5F00_12.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A partir de este punto podemos comenzar a enviar consultas al modelo utilizando cualquiera de los medios a nuestra disposici&amp;oacute;n: consultas DAX, consultas MDX o Excel. Todo ello ser&amp;aacute; tratado en la segunda parte de este art&amp;iacute;culo.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207337" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>PowerPivot, DAX and Excel. Business Intelligence for all audiences</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/09/17/powerpivot-dax-and-excel-business-intelligence-for-all-audiences.aspx</link><pubDate>Mon, 17 Sep 2012 19:25:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206773</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=206773</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=206773</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/09/17/powerpivot-dax-and-excel-business-intelligence-for-all-audiences.aspx#comments</comments><description>&lt;p&gt;(The spanish version of this article was previously published in &lt;a href="http://dnmplus.net/articulos/powerpivot-dax-y-excel-business-intelligence-para-todos-los-publicos.aspx"&gt;dNM+&lt;/a&gt;, issue 83)&lt;/p&gt;
&lt;p&gt;PowerPivot is a technology for information analysis whose peculiarity lies in the ability of working with massive amounts of data using Excel as user interface, so it becomes an attractive offer, given the popularity of this tool belonging to the Office suite. This article introduce the reader to PowerPivot as well as DAX (Data Analysis eXpressions), the analytical expression language that accompanies it, reeling off the most important features of this technology, which coupled with traditional Analysis Services and MDX (MultiDimensional eXpressions) language, make SQL Server 2012 one of the most robust and powerful solutions in the Business Intelligence arena.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;With increasing frequency, organizations must perform diverse analysis about their status in the most varied perspectives (business, financial, HR, etc.) and on an increasingly vast amount of data, for which require suitable tools to enable them to obtain a reliable and valid information of such state.&lt;/p&gt;
&lt;p&gt;As explained in this blog&amp;#39;s &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/07/31/olap-data-cubes-in-sql-server-2008-r2-analysis-services.aspx"&gt;article&lt;/a&gt;, OLAP data cubes are one of the key elements in this data analysis ecosystem called Business Intelligence (BI).&lt;/p&gt;
&lt;p&gt;However, a BI system, as occurs in other areas such as Web applications, desktop, etc., requires a development team and time to its creation, this latter factor sometimes extends for longer than initially estimated.&lt;/p&gt;
&lt;p&gt;Given the problems posed above, we can propose as a solution to improve development tools of the information system, which accelerate its creation time, and allow handling a greater data volume, given the widespread increase of this aspect in all corporate areas.&lt;/p&gt;
&lt;p&gt;It would also be necessary to promote the development team, incorporating new players into the system development cycle, which so far have played a role of mere validators, but they can bring great value to it, given his extensive knowledge about the structure of the various data sources available within the organization.&lt;/p&gt;
&lt;p&gt;PowerPivot comes with the aim of providing solutions to the challenges posed above, covering a number of specific areas in the development of an information system based on BI.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Self-service BI&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;When we talk about self-service, usually framed this concept within the product sales activity, where a person, the client, moves to a place, the supermarket, where products are exposed, and once there the client picks up the products, all generally without requiring the intervention of any intermediary.&lt;/p&gt;
&lt;p&gt;Within the BI context we can make an analogy with the self-service model, using a concept called &lt;i&gt;self-service BI,&lt;/i&gt; which advocates that end users (advanced or other profile) of an information system can elaborate their own analysis and reports on the system contents, to meet the specific needs emerging in several company departments, without having on these situations to rely from the enterprise BI development team.&lt;/p&gt;
&lt;p&gt;As requirements are the access need by these users to those data sources that require analysis and it is also crucial that self-service BI oriented applications have a learning curve as small as possible, so users can start being productive with them almost immediately.&lt;/p&gt;
&lt;p&gt;PowerPivot meet these requirements, since being a technology built into Excel has a wide user base already working with both, the functionality of the spreadsheet and access to external data sources, thus reducing or eliminating training in the use of user interface, and focuses on learning specific features about additional support for data analysis.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Incorporating new user profiles to the development cycle&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;In addition to release development teams a significant workload, providing self-service BI tools to end users; we get as a bonus the possibility that advanced users from various departments of the organization, through the use of such tools, to assist in the development cycle of the information system, providing ideas and suggestions.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;VertiPaq. High performance data processing engine&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;PowerPivot introduces a new data processing engine: VertiPaq, which through a column-based storage, implements a series of algorithms for data compression, by which is capable of loading millions of records in memory. &lt;/p&gt;
&lt;p&gt;However, due to the execution in memory nature of VertiPaq is recommended, whenever possible, work on a 64-bit environment, with adequate software version to this architecture: operating system, SQL Server, Office 2010, PowerPivot, etc., since it does not suffer the memory address limitations found in the 32-bit systems. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Architectural elements&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;PowerPivot, as seen in next image, consists of an assembly that is loaded into Excel process; VertiPaq engine, which handles data loading, query management and DAX expressions execution against the data warehouse, as well as PowerPivot&amp;#39;s pivot tables and charts, and finally, the OLAP provider, the Analysis Management Objects (AMO) objects and ADOMD.NET provider, allowing communication with analysis services, for gathering information from data cubes if applicable.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Collaboration environment. PowerPivot for SharePoint&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Using PowerPivot is expected that the number of analysis models created by users grows noticeably, and it is therefore very important to have a management mechanism, with respect to the publishing and access security within the organization.&lt;/p&gt;
&lt;p&gt;This is the purpose of &lt;i&gt;PowerPivot for SharePoint,&lt;/i&gt; a plug-in extending Excel Services for SharePoint, in the above paragraphs about management and collaboration.&lt;/p&gt;
&lt;p&gt;Additionally, &lt;i&gt;PowerPivot for SharePoint&lt;/i&gt; allows users to view PowerPivot models published in the organization simply using a web browser, so you only need to install Excel and &lt;i&gt;PowerPivot for Excel&lt;/i&gt; on the machines of users who will develop analytical models using this tool.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;PowerPivot. BISM cornerstone&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;(Note: for a more accurate description of BISM than below, we recommend read in first place the SSAS Tabular Models &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/09/11/sql-server-2012-analysis-services-tabular-models.aspx"&gt;article&lt;/a&gt; which includes updated information about this technology).&lt;/p&gt;
&lt;p&gt;SQL Server 2012 ships with a new BI model called Business Intelligence Semantic Model (BISM). This model doesn&amp;#39;t replace or displace Unified Dimensional Model (UDM), the existing BI model from SQL Server 2005 but coexist with it, complementing and enriching the SQL Server offer in BI area, allowing us to have both models to work with the one that best suits our needs.&lt;/p&gt;
&lt;p&gt;SQL Server has been traditionally blamed, referring to UDM, that its implementation in BI area has a difficult learning curve with complex concepts: cubes, dimensions, measures, etc., and that the time needed to develop a solution extends too much when it comes to creating a simple analysis system.&lt;/p&gt;
&lt;p&gt;From our point of view, this learning curve isn&amp;#39;t much more complicated than we find in other aspects of software development, although we admit that from the perspective of developers used to working with a relational data model, getting familiar with the UDM-OLAP multidimensional model to build a business analytics solution may involve some initial complexity until the developer master the concepts and features of the technology.&lt;/p&gt;
&lt;p&gt;BISM comes to solve this problem, providing a simpler way of work, distinguished by its relational philosophy supported by PowerPivot and VertiPaq. While BISM is primarily oriented to the development of self-service analytical solutions or for small teams, UDM is focused in the development of corporate BI solutions, which require more planning.&lt;/p&gt;
&lt;p&gt;BISM is a model with a distributed architecture in three layers: data access, business logic and data model.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The data access layer is responsible for connecting to data sources to load the data they contain, existing two ways to operate with them: cached or real time. In the case of cached mode, data is loaded using VertiPaq, whereas if we use the real-time mode, this task is left to the original data source from which data are extracted.&lt;/p&gt;
&lt;p&gt;The business logic layer will implement the managing and processing of data that allow us to make them relevant information. We will use for this any expression languages ​​at our disposal: DAX or MDX.&lt;/p&gt;
&lt;p&gt;DAX is the expression language for data analysis built-in PowerPivot. We&amp;#39;ll use it to build queries against the data store located in VertiPaq, while MDX is the language usually employed in UDM to query OLAP cubes.&lt;/p&gt;
&lt;p&gt;DAX is not as powerful as MDX, but it is much easier to use, and aims to query data located in a self-service BI model, which theoretically should not require the use of complex queries, reserved to be made against the corporate BI system, which under normal conditions will have been developed by UDM.&lt;/p&gt;
&lt;p&gt;Finally, the data model layer will be used by client applications (Excel, SharePoint, Reporting Services, etc.) gathering information from the proper model: relational or multidimensional. Among the reporting tools that use this model is Power View, a project whose objective is to provide a better user experience for data visualization and reporting against BISM based models.&lt;/p&gt;
&lt;p&gt;Some prominent voices in the BI-related technical &lt;a href="http://cwebbbi.wordpress.com/2010/11/11/pass-summit-day-2/"&gt;community&lt;/a&gt; have expressed concern about the UDM-OLAP position with the BISM arrival in SQL Server 2012, although from Analysis Services development team wanted to send a reassuring &lt;a href="http://blogs.technet.com/b/dataplatforminsider/archive/2010/11/12/analysis-services-roadmap-for-sql-server-denali-and-beyond.aspx"&gt;message&lt;/a&gt;, insisting that BISM is not a replacement for UDM but a complementary technology.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;PowerPivot in practice&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;After architectural features review made in previous paragraphs, it&amp;#39;s time to get down to working to develop a PowerPivot model, which help us to get our first impressions about the scope of this technology.&lt;/p&gt;
&lt;p&gt;First of all we need to have Office 2010 installed, and download and install PowerPivot for Excel &lt;a href="http://www.microsoft.com/en-us/download/details.aspx?id=7609"&gt;plug-in&lt;/a&gt;. In the event that our system is 32 bit, we&amp;#39;ll download the file PowerPivot_for_Excel_x86.msi, but if we work on a 64 bit we must download the file PowerPivot_for_Excel_amd64.msi. For the sake of testing, in this article we use a Windows 7 operating system virtual machine with 1.5 GB of RAM and Intel Core 2 Duo processor.&lt;/p&gt;
&lt;p&gt;Although the name of the download page referred to SQL Server 2008 R2, it is not necessary to have it installed if we are going to work with other data formats such as Access, text files, etc. However, in our case, we will use SQL Server as data engine and the database &lt;a href="http://www.microsoft.com/en-us/download/details.aspx?id=18279"&gt;ContosoRetailDW&lt;/a&gt;. Through the latter link we&amp;#39;ll download the ContosoBIdemoBAK.exe file containing the database in format backup.&lt;/p&gt;
&lt;p&gt;The reason why we use this database is that it has some tables with millions of records, allowing us to test one of the salient features of PowerPivot: the ability to handle large volumes of data.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creating a model&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;After restoring the database we&amp;#39;ll open Excel, then clicking on the ribbon tab &lt;i&gt;PowerPivot&lt;/i&gt;. Among the options on this tab we will click &lt;i&gt;PowerPivot window,&lt;/i&gt; belonging to &lt;i&gt;Launch&lt;/i&gt; group&lt;i&gt;,&lt;/i&gt; which as its name suggests, will open the PowerPivot working window.&lt;/p&gt;
&lt;p&gt;The first task in creating the model will be to connect to a data source to import its content, so that from the &lt;i&gt;Home&lt;/i&gt; tab of the PowerPivot window, in the &lt;i&gt;Get External Data&lt;/i&gt; group, we&amp;#39;ll click &lt;i&gt;From database&lt;/i&gt; option, selecting &lt;i&gt;From SQL Server&lt;/i&gt; among the available items.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As a result will open the &lt;i&gt;Table Import Wizard,&lt;/i&gt; where we&amp;#39;ll include information to connect to the database ContosoRetailDW. In the &lt;i&gt;Select Tables and Views&lt;/i&gt; step we will check FactSales, DimDate, DimStore and DimProduct.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;After this step will begin the import process, once completed will show each of the imported tables in different tabs in PowerPivot window.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Querying the model&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The set of tables we have just import will conduct an analysis of company sales, according to data related to the sales table: dates, products, stores, etc.&lt;/p&gt;
&lt;p&gt;To do this we will click on &lt;i&gt;PivotTable &lt;/i&gt;option in &lt;i&gt;Reports&lt;/i&gt; group reports, creating a PowerPivot&amp;#39;s PivotTable with which to perform our analysis operations. This action will move the focus to Excel window, where a dialog box will ask you the coordinates to place the PivotTable in the spreadsheet. Accepting the default values the new PivotTable will be created.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;On the pivot table&amp;#39;s right side we find the &lt;i&gt;PowerPivot Field List&lt;/i&gt; panel where we select the fields to use for our analysis, either as axis labels of rows and columns, numeric values, filters, and slicers.&lt;/p&gt;
&lt;p&gt;Those readers with expertise in creating OLAP cubes will verify that querying a PowerPivot model is very similar to the query against a data cube, but without the existence of a real cube, as in the field list panel, the items in block Values ​​represent the cube measures or metrics, while the rest of the block fields, represent the dimension attributes, displayed either in rows, columns or filter the PivotTable.&lt;/p&gt;
&lt;p&gt;We will begin creating our query by checking the field SalesAmount, from FactSales table. Due this is a numeric field, it will automatically be placed as a measure in the Values block. PowerPivot will apply then an addition operation on all records in the table to which it belongs.&lt;/p&gt;
&lt;p&gt;The current state of the PivotTable does not offer, however, great analytical possibilities, since we only have total by SalesAmount field. We need to add additional elements to the query relating to the table FactSales such as DimProduct table. This table contains each product&amp;#39;s name and additional information as manufacturer, type, color, size, etc.&lt;/p&gt;
&lt;p&gt;Suppose we want to find out the number of sales by product, but instead of using his name, we need to analyze by manufacturer. What we do in this case is check the field Manufacturer, belonging to the field list of DimProduct table. This action will place the field in the &lt;i&gt;Row Labels&lt;/i&gt; block and their values in the PivotTable row axis. In this way we will know how sales have meant by each of the manufacturers.&lt;/p&gt;
&lt;p&gt;Since the SalesAmount field values are not shown formatted, as additional work we right-click any cell in this field, choosing &lt;i&gt;Number Format...&lt;/i&gt; option. In the format dialog box select type Currency with two decimal places and euro symbol, being applied to all cells in this field in the pivot table.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Writing DAX expressions&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;As noted earlier, DAX is the expression language through which we&amp;#39;ll build the business logic in PowerPivot, both as PivotTable and data model.&lt;/p&gt;
&lt;p&gt;Before starting to write our first sentences in this language, we must know that without us aware of this, we have already written a DAX expression! If we right-click &lt;i&gt;Sum of SalesAmount&lt;/i&gt; in &lt;i&gt;Values&lt;/i&gt; block and select &lt;i&gt;Edit Measure...&lt;/i&gt;, a dialog box will open with the expression automatically created by PowerPivot&lt;/p&gt;
&lt;p&gt;=SUM(&amp;#39;FactSales&amp;#39;[SalesAmount])&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The creation of a DAX expression is very similar to writing a formula in Excel, since then the equal sign, write one or more functions with their corresponding parameters, forming the whole expression. In the expression currently under review, the SUM function will make a sum of SalesAmount field for all records in the table FactSales. If the table name has spaces or other special characters we enclose it in quotes, in other cases not necessary. With respect to the field name should always be enclosed in brackets.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s approach to writing our own expressions, through two major elements PowerPivot: computed columns and measures. &lt;/p&gt;
&lt;p&gt;First we will create a computed column in the table FactSales, to obtain the sales amount without discounting. To this end, in PowerPivot window we should be on the last available empty column, writing in the formula bar as follows:&lt;/p&gt;
&lt;p&gt;=FactSales[UnitPrice] * FactSales[SalesQuantity]&lt;/p&gt;
&lt;p&gt;To assist in the writing of expressions, the AutoComplete feature will suggest at all times a list of functions, tables and fields, depending on what we go on writing.&lt;/p&gt;
&lt;p&gt;After writing the expression, the new column will be filled with the resulting values. Double-clicking the column header we&amp;#39;ll assign the name ImporteSinDescuento, ending the creation of computed column.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_09.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Another way to create a computed column is to click on &lt;i&gt;Add&lt;/i&gt; option from &lt;i&gt;Columns&lt;/i&gt; group, belonging to &lt;i&gt;Design&lt;/i&gt; tab.&lt;/p&gt;
&lt;p&gt;Because the fields used in the formula belong to the same table on which we are creating the calculated column, in the expression syntax we can circumvent the name of the table, being as follows:&lt;/p&gt;
&lt;p&gt;=[UnitPrice] * [SalesQuantity]&lt;/p&gt;
&lt;p&gt;To use the new column in the pivot table we&amp;#39;ll back to the Excel window, finding a warning in &lt;i&gt;PowerPivot Field List&lt;/i&gt; which informs us that data was modified. Clicking the &lt;i&gt;Refresh&lt;/i&gt; button of the warning the field list will update, adding the new field ImporteSinDescuento, which we&amp;#39;ll check to include in the PivotTable.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_10.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Our next step is creating a measure to calculate, for each manufacturer, the percentage of his sales with respect to total sales of the company.&lt;/p&gt;
&lt;p&gt;In &lt;i&gt;PowerPivot&lt;/i&gt; tab, within &lt;i&gt;Measures&lt;/i&gt; group&lt;i&gt;,&lt;/i&gt; we click the &lt;i&gt;New Measure&lt;/i&gt; option, opening the &lt;i&gt;Measure &lt;/i&gt;&lt;i&gt;Settings&lt;/i&gt; window, where we&amp;#39;ll type PorcentajeVentas as measure&amp;#39;s name and the following expression in formula field:&lt;/p&gt;
&lt;p&gt;=SUM(FactSales[SalesAmount]) / CALCULATE(SUM(FactSales[SalesAmount]), ALL(FactSales))&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_11.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The first part of this expression, as we have seen, is responsible for adding the field SalesAmount. This sum will be made for each manufacturer, because this field is used in PivotTable labels row.&lt;/p&gt;
&lt;p&gt;The second part of the expression returns, for all rows, the total sum of SalesAmount field, which we accomplish combining the functions CALCULATE, SUM and ALL. CALCULATE function evaluates the expression passed as the first parameter, which is a sum of SalesAmount field, and requires that the sum is over all FactSales table records by using the ALL function, regardless of the filters that are applied in the PivotTable.&lt;/p&gt;
&lt;p&gt;Finally, add the new measure to the pivot table by applying the percentage format.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_12.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Filters and slicers&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Our PivotTable now shows arranged by product manufacturers, a series of measures obtained from fields and calculations of FactSales table belonging to PowerPivot data model.&lt;/p&gt;
&lt;p&gt;The results of these measurements are made from all records of that table, but at some point we may also be interested to have the ability to apply filters on the model&amp;#39;s information, in order to obtain different perspectives of analysis.&lt;/p&gt;
&lt;p&gt;PowerPivot pivot tables provide the user with filters and slicers as data filtering tools. Next, we&amp;#39;ll explain to the reader to use them as a means to narrow the results of the report.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s suppose we want to filter information in the pivot table depending on the type of store where are the products. We get this data from field StoreType in DimStore table.&lt;/p&gt;
&lt;p&gt;To create a filter of this type, in the field list pane we&amp;#39;ll open out the field list of table DimStore and drag the StoreType field to the &lt;i&gt;Report Filter&lt;/i&gt; block&lt;i&gt;. &lt;/i&gt;As a result this filter is inserted in the top of the pivot table.&lt;/p&gt;
&lt;p&gt;By clicking on the filter selecting values button, we&amp;#39;ll select &amp;quot;Almac&amp;eacute;n&amp;quot;. This action will activate the filter, causing all numeric cells in the pivot table refreshing sales information depending on the filter set.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_13.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Slicers, moreover, they behave as filters, although its handling by the user is slightly different.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s create a slicer that allows us to filter the results by sales year, for which we will drag the CalendarYear field from DimDate table and drop in &lt;i&gt;Slicers Horizontal&lt;/i&gt; block. This action will create the slicer with all filter values placed above the pivot table.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_14.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Slicer values ​​that appear in a darker color tone are those with which we can make effective filters, while the use of those with a lighter shade will not produce results as there are no sales in those years.&lt;/p&gt;
&lt;p&gt;If we want to use more than one value in the slicer, we must keep down the CTRL key while clicking on the different values. The result of the filter is not effective until we release the CTRL key. To remove all filters from the segmentation will click the funnel-shaped icon situated at the top right.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creating a PivotChart&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;In certain circumstances, the numerical data provided by a PivotTable it may not be sufficient to analyze the content of a PowerPivot model, so we also have pivot charts at our disposal, as an alternative in the information display.&lt;/p&gt;
&lt;p&gt;We can create a pivot chart from scratch or use an existing pivot table as chart&amp;#39;s foundation. In this case we&amp;#39;ll choose the latter method, for which, once positioned in the pivot table, we&amp;#39;ll click on &lt;i&gt;Options&lt;/i&gt; tab belonging to &lt;i&gt;PivotTable Tools &lt;/i&gt;category&lt;i&gt;,&lt;/i&gt; and then select &lt;i&gt;PivotChart&lt;/i&gt; option, located in the group &lt;i&gt;Tools. &lt;/i&gt;This opens the &lt;i&gt;Insert Chart&lt;/i&gt; dialog box, offering us a wide range of chart types to insert into the worksheet. Having made our choice, we will accept this dialog inserting the chart next to the PivotTable.&lt;/p&gt;
&lt;p&gt;From this point, both the table and chart will be synchronized, so that the modifications of filters, measures axes labels, etc. performed in one will be reflected immediately in the other. Next image shows the appearance of our report including pivot table and pivot chart.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/PowerPivotDAXExcelBusinessIntelligenceAllAudiences_5F00_15.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Conclusions&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;PowerPivot represents a technology with great potential to become an important part of the toolkit available for BI development with SQL Server. If we add capacity in handling large volumes of data, the power of its query expressions language, and the fact of using Excel as user interface, we obtain a product that allows users to create their own analysis models to address specific information needs. At the same time, these models can be of assistance to BI development teams in building corporate information systems.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206773" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx">PowerPivot</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>SQL Server 2012 Analysis Services Tabular Models</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/09/11/sql-server-2012-analysis-services-tabular-models.aspx</link><pubDate>Tue, 11 Sep 2012 19:37:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206710</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=206710</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=206710</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/09/11/sql-server-2012-analysis-services-tabular-models.aspx#comments</comments><description>&lt;p&gt;(The spanish version of this article was previously published in &lt;a href="http://dnmplus.net/"&gt;dNM+&lt;/a&gt;, issue 93)&lt;/p&gt;
&lt;p&gt;The recent SQL Server 2012 release (formerly codenamed Denali) is accompanied, as usual in any new version, for several interesting improvements. In this article we&amp;#39;ll focus on development of analytical tabular models, an integral part of Business Intelligence Semantic Model (BISM), the new paradigm for developing Business Intelligence (BI) solutions based on SQL Server 2012 Analysis Services.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As was already mentioned in the introductory &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/09/17/powerpivot-dax-and-excel-business-intelligence-for-all-audiences.aspx"&gt;article&lt;/a&gt; about PowerPivot, the incorporation of BISM into Analysis Services makes SQL Server one of the most powerful solutions within the current BI arena. However, since the first public announcements about BISM so far, new details have been revealed about the architecture of this technology, allowing us to be more precise in the descriptions of it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;BISM. A single model for all analytical needs&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;BISM becomes the new model for the development of BI solutions that fulfills the analysis requirements of all kind users.&lt;/p&gt;
&lt;p&gt;BISM represents an evolution from Unified Dimensional Model (UDM) towards a combined model that offers all UDM multidimensional development features plus new features based on a relational analysis engine, what enrich the current SQL Server offer in the analytical services area. Therefore, from now on, the term UDM is replaced for BISM, when we mention the development model used by Analysis Services. Similarly, when we update an UDM project to SQL Server 2012, it will be deemed as a BISM project for all purposes.&lt;/p&gt;
&lt;p&gt;This integration between work philosophies, and hence on the underlying technologies (multidimensional and relational), results in an architecture distributed in three layers, as we see in the following image, with response capacity to users with very different needs in all concerning tasks related to data analysis.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Watching the workflow of this architecture in a bottom-top direction, in first place, we find the &lt;i&gt;data access&lt;/i&gt; layer, which is responsible for performing the information extraction resident in the data sources we connect, existing two modes for this extraction: &lt;i&gt;cache&lt;/i&gt; and &lt;i&gt;passthrough&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;The caching mechanism gets the data from the original source and stored it in a data structure based on a compression algorithm optimized for high-speed access. In turn, using this cache mode we must choose two different storage engines: &lt;i&gt;MOLAP&lt;/i&gt; or &lt;i&gt;xVelocity&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;MOLAP is the intermediate storage system traditionally used in Analysis Services, and as the name suggests, is optimized for use in multidimensional models development (OLAP cubes).&lt;/p&gt;
&lt;p&gt;xVelocity is a brand new system introduced with BISM for use in tabular models, consisting of a column based data storage engine, which combines sophisticated compression and search algorithms, to offer, without using indexes or aggregations, excellent performance in speed response to our queries.&lt;/p&gt;
&lt;p&gt;Regarding to passthrough mode, as its name implies, sends the query directly to data source engine, so both operations: data processing and business logic are performed there. In this case there are two modes of execution too: &lt;i&gt;ROLAP&lt;/i&gt; and &lt;i&gt;DirectQuery&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;ROLAP mode is usually used by Analysis Services, which uses the data source itself to process queries against cubes belonging to multidimensional models.&lt;/p&gt;
&lt;p&gt;DirectQuery is used in tabular models to also process queries in the data source.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Business logic&lt;/i&gt; layer includes queries in MDX ​​or DAX languages with which we&amp;#39;ll implement our solution&amp;#39;s logic, depending whether we work respectively against a multidimensional or tabular model.&lt;/p&gt;
&lt;p&gt;Finally, in the &lt;i&gt;data model&lt;/i&gt; layer we find the conceptual part of this architecture, where using SQL Server Data Tools (formerly Business Intelligence Development Studio and current development environment based on Visual Studio 2010) will build our model using one of the available project templates: &lt;i&gt;Analysis Services Multidimensional and Data Mining Project&lt;/i&gt; or&lt;i&gt; Analysis Services Tabular Project.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth mentioning that it is also possible to use PowerPivot as development tool for a tabular model, but to deploy it in the server it&amp;#39;s mandatory to use SQL Server Data Tools.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Installing Analysis Services. A semantic model, two modes of execution&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Due to the particular features of each BISM data model, in SQL Server 2012 setup, at Analysis Services step, we must choose which analysis server execution mode we want to install: &lt;i&gt;Multidimensional&lt;/i&gt; or &lt;i&gt;Tabular&lt;/i&gt;, because it is not possible to install both simultaneously in the same instance. For this reason the recommended procedure is to install separate instances. However, in our case it is sufficient to install only the tabular mode for the development of this example.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Let&amp;#39;s get started. Creating a tabular model&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Exposed all necessary aspects to conceptually locate the reader within the new semantic model, let&amp;#39;s get into the practical part of the article, in which we will develop a tabular analysis project.&lt;/p&gt;
&lt;p&gt;We will use the sample database &lt;a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"&gt;AdventureWorksDWDenali&lt;/a&gt; being the model&amp;#39;s goal to analyze the shipping orders expenses placed by customers through the Internet and the number of orders issued, all according customer&amp;#39;s residence location and promotion details about items purchased.&lt;/p&gt;
&lt;p&gt;In first place we will start SQL Server Data Tools, creating a new project based on &lt;i&gt;Analysis Services Tabular Project&lt;/i&gt; template, giving it the name PruebaModeloTabular. As we shall see in &lt;i&gt;Solution Explorer,&lt;/i&gt; this project will consist of a file named Model.bim, which represents the tabular model designer.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The next step will be to add tables to the model, so we&amp;#39;ll select the menu option &amp;quot;Model | Import From Data Source&amp;quot;, which will start the data import wizard. After choosing the type of data source, SQL Server instance and database, we reach the step where we must enter credentials to connect to the data source and proceed with data extraction.&lt;/p&gt;
&lt;p&gt;At this point we&amp;#39;ll use our Windows account (in case we have adequate access permissions) or choose the &lt;i&gt;Service Account&lt;/i&gt; option, which will use the NT SERVICE\MSOLAP$SQL2012TAB account (SQL2012TAB is the SQL Server instance name of my machine) associated with the Analysis Services service. If we use the latter possibility, we need to grant access and read permissions to this account on the AdventureWorksDWDenali database.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To assign that permission, in &lt;i&gt;SQL Server Management Studio&lt;/i&gt; we right-click the &lt;i&gt;Logins&lt;/i&gt; node, belonging in turn to &lt;i&gt;Security&lt;/i&gt; node, choosing &lt;i&gt;New Login&lt;/i&gt; option&lt;i&gt;, &lt;/i&gt;which will open the dialog box to add a new login to the server, where we&amp;#39;ll type the Analysis Services account name. In &lt;i&gt;User Mapping&lt;/i&gt; section we&amp;#39;ll check the database to grant access.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Continuing the import wizard we&amp;#39;ll reach the selection table step, where we&amp;#39;ll check DimSalesTerritory, DimPromotion and FactInternetSales tables, and proceeded to start the import process.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;When the data import process finishes, the designer will show the tables in a grid, arranging them into tabs.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This display mode can be switched to a diagram mode, more suitable if we want to focus on concrete elements such as relationships between tables. To change the view mode use the buttons for that purpose in the bottom right of the designer window. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creating measures&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Despite having imported tables to the model, we still can&amp;#39;t conduct a proper analysis on it, because we lack the calculations (measures in BI context) responsible for providing numerical results, essential in any system of this type, as we saw in the &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/07/31/olap-data-cubes-in-sql-server-2008-r2-analysis-services.aspx"&gt;article&lt;/a&gt; about OLAP Cubes.&lt;/p&gt;
&lt;p&gt;To create a measure for the model, we must firstly set the designer&amp;#39;s display to grid (default mode). Once this adjustment is made, we see that each table shows two sections: top, which contains the rows of the table itself, and bottom, reserved for calculated measures created by the model developer.&lt;/p&gt;
&lt;p&gt;Next we&amp;#39;ll select the FactInternetSales table (also known as fact table in multidimensional context) that contains those columns that can be used in obtaining numerical results.&lt;/p&gt;
&lt;p&gt;We will use the Freight column to create the first of our measures: sum of the values ​​in that column for table&amp;#39;s rows. In grid&amp;#39;s bottom area we&amp;#39;ll select an empty cell for the column above mention, then we&amp;#39;ll click the toolbar&amp;#39;s Sum button, which apply the DAX language formula &amp;quot;SUM([Freight])&amp;quot; to the column.&lt;/p&gt;
&lt;p&gt;As a result of this operation we&amp;#39;ll obtain the &lt;i&gt;Sum of Freight&lt;/i&gt; measure, but we&amp;#39;ll change this name, assigned automatically by the development environment, to GastosTransporte, using the properties window.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_09.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Watching the resulting figure we will realize that there&amp;#39;s a formatting problem with the obtained value (7,339,696,091.00 &amp;euro;), as the correct result is 733969.6091. We can verify this running the following query in SQL Server Management Studio.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SELECT SUM(Freight) FROM FactInternetSales&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;However, we&amp;#39;ll find this difficulty only in model designer scope, since as we shall see in the next section, when analyze it from an external tool, the values ​​are displayed correctly.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Next we will create the measure to calculate the orders quantity issued by the company, so we&amp;#39;ll apply to SalesOrderNumber column a distinct count operation, because the FactInternetSales table can have more than one row for the same order.&lt;/p&gt;
&lt;p&gt;We can drop-down the Sum button in Visual Studio&amp;#39;s toolbar, so we can choose some of the most common calculations, &lt;i&gt;Distinct Count&lt;/i&gt; among them, but this time we&amp;#39;ll manually create the measure FacturasEmitidas, writing the DAX expression &amp;quot;FacturasEmitidas:=DistinctCount([SalesOrderNumber])&amp;quot; in the formula bar.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Analyzing the model from Excel&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;If we have Excel 2010 installed we can use it as analysis tool for the model we are developing. All we have to do is select the menu option &amp;quot;Model | Analyze in Excel&amp;quot; and Visual Studio will open Excel, loading the model in a PivotTable.&lt;/p&gt;
&lt;p&gt;On the pivot table panel &lt;i&gt;PivotTable Field List&lt;/i&gt; we will check the GastosTransporte measure, which will be located in the block &lt;i&gt;Values. &lt;/i&gt;Similarly we&amp;#39;ll proceed with SpanishPromotionCategory field from DimPromotion table, but this time we&amp;#39;ll place it on &lt;i&gt;Column Labels&lt;/i&gt; block&lt;i&gt;. &lt;/i&gt;Finally, fields SalesTerritoryGroup and SalesTerritoryCountry from DimSalesTerritory table will be placed in &lt;i&gt;Row Labels&lt;/i&gt; block, so that we can watch this information into a hierarchical fashion.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/SQLServer2012AnalysisServicesTabularModels_5F00_10.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;At the same time we can analyze the amount of bills issued by the company for sold items, adding FacturasEmitidas measure to the PivotTable, so we also get this information by the fields currently located in rows and columns or by other fields belonging to the model.&lt;/p&gt;
&lt;p&gt;Those readers who have had the opportunity to use PowerPivot will find interesting similarities with this way of work, since in both cases the underlying technology is the same.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Conclusions&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Tabular analysis models belonging to BISM, the new paradigm in building BI solutions, shipped with SQL Server 2012, are a great tool to develop powerful information systems using SQL Server Analysis Services. In this article we have made ​​an introduction to this interesting technology, showing the reader how to take advantage from it.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206710" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Configurar las credenciales de acceso a la fuente de datos en un modelo tabular de SQL Server 2012</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/09/04/configurar-las-credenciales-de-acceso-a-la-fuente-de-datos-en-un-modelo-tabular-de-sql-server-2012.aspx</link><pubDate>Mon, 03 Sep 2012 22:30:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206650</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=206650</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=206650</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/09/04/configurar-las-credenciales-de-acceso-a-la-fuente-de-datos-en-un-modelo-tabular-de-sql-server-2012.aspx#comments</comments><description>&lt;p&gt;Durante el desarrollo de un proyecto de an&amp;aacute;lisis de tipo tabular en SQL Server 2012 empleando &lt;i&gt;SQL Server Data Tools&lt;/i&gt;, al ejecutar el asistente &lt;i&gt;Table Import Wizard&lt;/i&gt;, que realiza la importaci&amp;oacute;n de datos al modelo tabular (opci&amp;oacute;n de men&amp;uacute; &amp;quot;Model | Import From Data Source&amp;quot;), en el caso de que nuestra fuente de datos sea una base de datos SQL Server y en el paso &lt;i&gt;Connect to a Microsoft SQL Server Database&lt;/i&gt; hayamos elegido conectarnos mediante autenticaci&amp;oacute;n de Windows, deberemos indicar, dentro del paso &lt;i&gt;Impersonation Information&lt;/i&gt;, las credenciales de acceso a dicha base de datos, para que el proceso de importaci&amp;oacute;n se realice de forma satisfactoria.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Por defecto, el asistente de importaci&amp;oacute;n en el mencionado paso &lt;i&gt;Impersonation Information&lt;/i&gt; utiliza la informaci&amp;oacute;n de la cuenta del usuario actual (nombre de usuario y contrase&amp;ntilde;a) para conceder o denegar el acceso a la base de datos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Sin embargo, podemos elegir que sea la cuenta asignada al servicio de Analysis Services la que se utilice para conceder acceso al origen del que extraeremos los datos que formar&amp;aacute;n parte del modelo tabular; procedimiento que describiremos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como primera consideraci&amp;oacute;n, la cuenta asociada al servicio de Analysis Services tiene el siguiente formato:&lt;/p&gt;
&lt;p&gt;NT Service\MSOLAP$NombreInstancia&lt;/p&gt;
&lt;p&gt;Por lo que si nos encontramos trabajando contra una instancia cuyo nombre es, por ejemplo, SQLTABULAR, el nombre de la cuenta ser&amp;aacute;:&lt;/p&gt;
&lt;p&gt;NT Service\MSOLAP$SQLTABULAR&lt;/p&gt;
&lt;p&gt;Por otro lado, supongamos que la base de datos con la que vamos a trabajar en la creaci&amp;oacute;n de nuestro modelo tabular es ContosoRetailDW, disponible en el siguiente &lt;a href="http://www.microsoft.com/es-es/download/details.aspx?id=18279"&gt;enlace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Para establecer los oportunos permisos de acceso de la cuenta NT Service\MSOLAP$SQLTABULAR sobre esta base de datos, iniciaremos &lt;i&gt;SQL Server Management Studio&lt;/i&gt; y nos conectaremos al motor de base de datos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n desplegaremos el nodo &lt;i&gt;Security&lt;/i&gt;, y dentro de este, el nodo &lt;i&gt;Logins&lt;/i&gt;, donde veremos las cuentas que actualmente tienen asignado alg&amp;uacute;n tipo de permiso de acceso. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Haciendo clic derecho en el nodo &lt;i&gt;Logins&lt;/i&gt;, seleccionaremos la opci&amp;oacute;n &lt;i&gt;New Login&lt;/i&gt;, que abrir&amp;aacute; el cuadro de di&amp;aacute;logo de creaci&amp;oacute;n del login, en cuyo apartado &lt;i&gt;General&lt;/i&gt; escribiremos el nombre de la cuenta de servicio de Analysis Services, que utilizar&amp;aacute; autenticaci&amp;oacute;n de Windows para identificarse.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el apartado &lt;i&gt;User Mapping&lt;/i&gt; haremos clic en la casilla correspondiente a la base de datos ContosoRetailDW, y en la parte inferior estableceremos el modo de acceso a la misma: propietario, lectura, escritura, etc.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Aceptando el cuadro de di&amp;aacute;logo, la cuenta de servicio de Analysis Services se a&amp;ntilde;adir&amp;aacute; al conjunto de logins del servidor SQL Server, con lo que ya podremos importar las tablas de la base de datos ContosoRetailDW a trav&amp;eacute;s de dicha cuenta en el asistente de importaci&amp;oacute;n de modelos tabulares.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201209/ConfigurarCredencialesAccesoFuenteDatosModeloTabular_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Espero que os resulte de utilidad.&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206650" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category></item><item><title>OLAP Data cubes in SQL Server 2008 R2 Analysis Services</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/07/31/olap-data-cubes-in-sql-server-2008-r2-analysis-services.aspx</link><pubDate>Tue, 31 Jul 2012 19:45:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206327</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=206327</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=206327</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/07/31/olap-data-cubes-in-sql-server-2008-r2-analysis-services.aspx#comments</comments><description>&lt;p&gt;(The spanish version of this article was previously published in &lt;a href="http://www.dnmplus.net/articulos/cubos-de-datos-en-sql-server-2008-analysis-services.aspx"&gt;dNM+, issue 77&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;It is an undeniable fact that in recent times, the volume of data that organizations must manage has soared. Analyze so much data; in order to make strategic decisions has become a real problem. In this article we will make an introduction to OLAP data cubes in SQL Server 2008 R2 Analysis Services, a powerful tool that can transform vast amounts of data into useful information.&lt;/p&gt;
&lt;p&gt;The excessive increase of the volume of data into information systems of a company, without proper organization and structure, can have negative effects such as slow in their status analysis, or worse, lead to inappropriate strategic decision making, since having millions of records distributed across multiple heterogeneous data sources (SQL Server and Access databases, flat files, Excel spreadsheets, etc..), need not be synonymous in all cases of a system that provides quality information.&lt;/p&gt;
&lt;p&gt;To solve such problems we have the so-called Business Intelligence (BI) tools, and in the case we are working with SQL Server, one of its main components: SQL Server Analysis Services (SSAS), allow us to create a data cube, an element by which to generate information to analyze the state of the company from all its data sources.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Conceptual&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;From a conceptual perspective, a data cube is one more part into the gear of an information system called data warehouse. The cube is provided with internal machinery that can process high volumes of data in a relatively short period of time, and whose goal is always to obtain a numerical result (amount of sales, expenses, number of products sold, etc.). These results may change depending on one or more filters that apply on the cube. The response time is minimal because the cube processing engine precalculates the possible combinations of results that the user can request. The numerical results obtained are called measures, while the elements used to sort / filter information are called dimensions.&lt;/p&gt;
&lt;p&gt;Represented graphically, a data cube is shown as the geometric shape which takes its name, horizontally and vertically partitioned into a series of divisions that give rise to multiple cells, which identify each of the possible outcomes of the measures, obtained by the intersection in each cell of the dimensions that make up the cube. Next figure shows such a graphical representation of a cube, with sales information by product, employees and currency. On the cube sides are placed the dimensions, whose cross produces numerical results in the cells.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Watching the previous figure, the reader may think that the number of dimensions in a cube is limited to those we represent through that geometric shape. Nothing is further from reality, since a cube can withstand a high number of dimensions, which loosely cover the requirements of the information to be obtained.&lt;/p&gt;
&lt;p&gt;We can find additional information about the conceptual aspects in a series of &lt;a href="http://www.dnmplus.net/articulos/sql-server-analysis-services-hola-cubo-i.aspx"&gt;articles&lt;/a&gt; on data cubes in SQL Server, previously appeared in this publication.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Main elements in a data warehouse&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;As mentioned above, a data cube is one of the pieces of a more complex architecture: the data warehouse, in which creative process involved several components, which are responsible to take the original data in the rough and polish it until it becomes in information ready for analysis. Next figure shows a diagram where we can see the phases of this transformation process.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Broadly depicted, this process performs, in first place, an operation of extraction, processing and loading data from source origin, located in the operational area, to a database located in the ​​integration area, using SQL Server Integration Services (SSIS) packages, which also performed data cleaning tasks.&lt;/p&gt;
&lt;p&gt;Then we would pass to the cube construction phase, which we will develop using SQL Server Analysis Services (SSAS). Finally, we reach the stage of cube query by end users, using several products such as SQL Server Reporting Services (SSRS), Excel, etc.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Physical elements. Fact and dimension tables&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;At the physical level, to build a data cube we need a database containing a table called &lt;i&gt;fact table&lt;/i&gt;, whose structure is formed by a series of fields, called &lt;i&gt;measurement fields&lt;/i&gt;, from which we obtain the cube&amp;#39;s numerical results; and on the other hand, a set of fields called &lt;i&gt;dimension fields&lt;/i&gt;, that we will use to join with the dimension tables, in order to get filtered results for the several dimensions integrating the cube.&lt;/p&gt;
&lt;p&gt;The other main foundation in the cube creation is made ​​from the &lt;i&gt;dimension tables&lt;/i&gt;. For each dimension or query / filter category we incorporate into our cube will need a table that will join with the fact table by a key field. This dimension table will act as a catalog of values, also called &lt;i&gt;attributes&lt;/i&gt;, which will be used independently or combined with other dimensions, to obtain results with greater accuracy.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Developing a data cube&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Once explained the necessary basics, we enter into the practical part of the article, where we&amp;#39;ll develop our own data cube. We will focus all our efforts exclusively on the cube creation, without addressing the extraction, transformation and loading operations, which would be made ​​using SSIS packages, since the latter are issues that fall outside the scope of this article, pending a future delivery.&lt;/p&gt;
&lt;p&gt;First, from Windows Start menu we&amp;#39;ll launch &lt;i&gt;SQL Server Business Intelligence Development Studio&lt;/i&gt;, which is located in Microsoft SQL Server 2008 R2 program group. This is a special version of Visual Studio for BI projects development. In the starting dialog we&amp;#39;ll select &lt;i&gt;Analysis Services Project&lt;/i&gt; as project template, giving it the name CuboDatosAdvWorks.&lt;/p&gt;
&lt;p&gt;Then right-click &lt;i&gt;Data Sources&lt;/i&gt; node in the Solution Explorer and select &lt;i&gt;New Data Source &lt;/i&gt;option, which opens the wizard to create the cube data source, which in our case will be the test database AdventureWorksDW2008 available in &lt;a href="http://msftdbprodsamples.codeplex.com/releases/view/55926"&gt;CodePlex&lt;/a&gt;, whose structure is ready to be used in data cubes design.&lt;/p&gt;
&lt;p&gt;We will leave the default options in the wizard until the connection to the data source step, selecting AdventureWorksDW2008. On reaching the wizard final step will see a summary of the data source we have created.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Our next step is to create a view of the data source, allowing us, as his name suggests, define a custom view of the database, including the tables we need to create the cube.&lt;/p&gt;
&lt;p&gt;In this sample cube we&amp;#39;ll measure the amount of sales that AdventureWorks company resellers have invoiced. Being possible query / filter the results by currency type in which the sale was made, and geographic area where the order was sent. We will use FactResellerSales as fact table, and DimSalesTerritory and DimCurrency as dimension tables.&lt;/p&gt;
&lt;p&gt;By right-clicking the &lt;i&gt;Data Source Views&lt;/i&gt; node in Solution Explorer, we&amp;#39;ll select &lt;i&gt;New Data Source View&lt;/i&gt; option, which opens a wizard in which first step we will choose the data source we just created. In the second step we&amp;#39;ll select the tables just mentioned.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Once finished this wizard it will display its design window where we see a diagram of the selected tables, with the existing relationships between them.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Building dimensions. Basic dimension&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The next step is to create the dimension that allows us to query / filter the cube information by order payment currency. Right clicking on the &lt;i&gt;Dimensions&lt;/i&gt; node of Solution Explorer, we&amp;#39;ll select the &lt;i&gt;New Dimension&lt;/i&gt; option, starting the wizard as usual. In his first step &lt;i&gt;Select Creation Method&lt;/i&gt;, we&amp;#39;ll leave the default option &lt;i&gt;Use an existing table&lt;/i&gt;. Upon entering step &lt;i&gt;Specify Source Information&lt;/i&gt;, three drop-down lists allow us to configure the information to be obtained for the dimension: &lt;i&gt;Main table&lt;/i&gt; to choose the table that use in the dimension: DimCurrency; &lt;i&gt;Key columns&lt;/i&gt; to indicate the primary key; and finally, &lt;i&gt;Name column&lt;/i&gt;, selecting CurrencyName field, which identifies the attribute to be displayed.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In the &lt;i&gt;Select Dimension Attributes&lt;/i&gt; step, the wizard will offer &lt;i&gt;Currency Key&lt;/i&gt; as an attribute of the dimension, which we will use, but changing its name to Currency. An attribute is a field, normal or calculated, belonging to the dimension table that is shown as a label anywhere in the dimension involved as part of a query against the data cube.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;At the last step we shall give the name Currency to the dimension, finishing the wizard. The dimension designer will show now with the structure we just created. Among all the properties of the attribute Currency, the most important are Name, which contains the name that will appear in queries against the cube; KeyColumns, which contains the key field in the table that relates to the fact table, and NameColumn, containing the field of the table that shows the attribute&amp;#39;s value.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In case we need to add more attributes to the dimension, just drag and drop fields from the table in &lt;i&gt;Data Source View&lt;/i&gt; pane to the Attributes pane of the designer.&lt;/p&gt;
&lt;p&gt;When attribute creation is finished, we&amp;#39;ll process the dimension by clicking the Process button on the toolbar&amp;#39;s designer, or through the Visual Studio &lt;i&gt;Build | Process&lt;/i&gt; menu. When the processing dimension is completed, we will click on the designer&amp;#39;s Browser tab, where we&amp;#39;ll inspect its contain.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_09.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Building dimensions. Hierarchical dimension&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;In addition to the single level dimensions, as we just saw in the previous section, we can create dimensions that group data on multiple levels, which provide a greater ability to disaggregate the cube information when consulted through a dimension of this type. This element is called a &lt;i&gt;dimension hierarchy&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take DimSalesTerritory table from our &lt;i&gt;Data Source View&lt;/i&gt; sample project. We can see that the combination of SalesTerritoryGroup, SalesTerritoryCountry and SalesTerritoryRegion fields allow us to establish several grouping levels.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_10.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Suppose we need to create a dimension based on this table to obtain, starting from SalesTerritoryGroup field, a hierarchical level display effect.&lt;/p&gt;
&lt;p&gt;To do this, we will create the dimension using the wizard in the way explained in previous section. The default attribute selected by the wizard will correspond to table&amp;#39;s primary key: SalesTerritoryKey field.&lt;/p&gt;
&lt;p&gt;Once located in the dimension designer, drag from the table in &lt;i&gt;Data Source View&lt;/i&gt; pane the SalesTerritoryGroup, SalesTerritoryCountry and SalesTerritoryRegion fields, and drop on the Attributes panel of the same designer.&lt;/p&gt;
&lt;p&gt;Then drag the Sales Territory Group attribute to the Hierarchies pane, which will create a new hierarchy. We&amp;#39;ll change its default name by Sales Territory. Also in this hierarchy will drop the Sales Territory Country and Sales Territory Region, noting that next to the hierarchy name appears a warning icon which informs us that relationships between the hierarchy attributes aren&amp;#39;t properly created, which can negatively affect the dimension processing.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_11.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To solve this problem we will click the &lt;i&gt;Attribute Relationships&lt;/i&gt; tab, where we see the relationships between attributes automatically created by the designer.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_12.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;These relationships, however, are not valid for our purposes, so we&amp;#39;ll select their representing arrows in the diagram and delete them. To create the new relationships drag from source attribute to destination, to leave them as see in next figure.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_13.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Before dimension processing let&amp;#39;s back to the &lt;i&gt;Dimension Structure&lt;/i&gt; tab to verify that the warning is gone. On the other hand we&amp;#39;ll select all attributes of the Attributes panel, assigning the False value on his property AttributeHierarchyVisible, so we&amp;#39;ll get independent attributes are not shown, since what interests us here is to explore only the hierarchy. Next figure shows the dimension result, with all elements of the hierarchy expanded.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_14.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Cube Building&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We reached the final stage in the development of our sample project: building the data cube. We will begin by right-clicking the Cubes node in Solution Explorer and selecting the &lt;i&gt;Add Cube&lt;/i&gt; option, which will open the creation wizard, leaving the default values ​​until the &lt;i&gt;Select Measure Group Tables&lt;/i&gt; step, which as its name suggests, it asked us to select the table containing the fields that we use as measures for the cube, i.e. the fact table, which in this case will be FactResellerSales.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_15.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Clicking Next, go into the &lt;i&gt;Select Measures&lt;/i&gt; step, where we have to select the fields that serve as cube measures. The goal of this cube is to ascertain the sales amount made ​​by resellers, therefore, we&amp;#39;ll select only the SalesAmount field.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_16.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The next step prompts us to select the dimensions that will be part of the cube. It automatically detected the dimensions created by us earlier, which already are offered selected by default.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_17.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The wizard performs then a search in the fact table to find a field that could also be capable of being treated as a dimension. Since we don&amp;#39;t need this feature, we&amp;#39;ll uncheck the selection of the fact table as source for the creation of dimensions. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_18.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;And now the final step, where we will give the name VentasDistribuidores to the cube, ending the wizard. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_19.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As a result the cube designer displays itself, showing various key elements, such as the dimensions pane, table diagram, measures, etc.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_20.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In the Measures pane appears the measure selected in the wizard, but we&amp;#39;ll change its name to &lt;i&gt;Importe Ventas&lt;/i&gt; in properties window. In this same window we can watch the name, aggregate function used to calculate the measure, used table field, format string, and so on.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_21.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For the measure to appear correctly formatted, in addition to assigning a value to the FormatString property, in the cube properties we have to assign the value &lt;i&gt;Spanish (Spain)&lt;/i&gt; to the Language property.&lt;/p&gt;
&lt;p&gt;Finally, before we can see the cube, as we did with the dimensions, we must process it by clicking the Process button, which opens the dialog box cube processing where we&amp;#39;ll click&amp;nbsp;the Run button. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_22.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Once the cube has been processed, we can see its contents by clicking on the Browser tab. In the &lt;i&gt;Measure Group&lt;/i&gt; pane we&amp;#39;ll expand the Measures node up to the &lt;i&gt;Importe Ventas &lt;/i&gt;measure, which drag into the central area of the display. Then drag the SalesTerritory dimension to the display&amp;#39;s left margin. We can right click on this dimension, selecting &lt;i&gt;Expand Items&lt;/i&gt; option, resulting in a display of the dimension elements. Finally drag the Currency dimension to the upper margin. As a result we get a data grid where each cell displays the measure for the intersection of the dimensions placed in columns and rows of data display.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201207/OLAPDataCubesSQLServer2008R2AnalysisServices_5F00_23.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Conclusions&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;In this article we have made ​​an introduction to the development of data cubes with SQL Server 2008 Analysis Services, a component of SQL Server product family intended to provide business intelligence solutions that exploit the analytics potential that lies in data&amp;#39;s company. The possibilities and power of this tool are enormous, and we encourage the reader to implement them.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206327" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx">SQL Server 2008 R2</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category></item><item><title>The importance of relationships in SQL Server 2012 tabular models</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/06/22/the-importance-of-relationships-in-sql-server-2012-tabular-models.aspx</link><pubDate>Fri, 22 Jun 2012 21:44:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:205723</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=205723</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=205723</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/06/22/the-importance-of-relationships-in-sql-server-2012-tabular-models.aspx#comments</comments><description>&lt;p&gt;An essential feature in BISM (Business Intelligence Semantic Model) tabular data models, the new BI development paradigm built in SQL Server 2012, are the relationships between tables of a particular model, because without them it would be impossible perform a proper analysis of the information contained therein.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say we have a database named AdvWksDW, created from some of the tables belonging to &lt;a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"&gt;AdventureWorksDW2012&lt;/a&gt; database, but without the corresponding relations between them. The following code block shows the SQL statements necessary for its creation.&lt;/p&gt;
&lt;p&gt;CREATE DATABASE AdvWksDW&lt;/p&gt;
&lt;p&gt;GO&lt;/p&gt;
&lt;p&gt;USE AdvWksDW&lt;/p&gt;
&lt;p&gt;GO&lt;/p&gt;
&lt;p&gt;SELECT * FROM INTO FactInternetSales AdventureWorksDW2012. Dbo.FactInternetSales&lt;/p&gt;
&lt;p&gt;GO&lt;/p&gt;
&lt;p&gt;SELECT * FROM INTO DimDate AdventureWorksDW2012. Dbo.DimDate&lt;/p&gt;
&lt;p&gt;GO&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For those readers familiar working with multidimensional analysis models, if we were to build an OLAP cube using this database, the FactInternetSales table represents &lt;i&gt;the fact table&lt;/i&gt; because it contains the columns from which we obtain measures or analyze numerical results, while DimDate table represents a &lt;i&gt;dimension table,&lt;/i&gt; used to filter the information by the dates in the model.&lt;/p&gt;
&lt;p&gt;Then we&amp;#39;ll create a tabular analysis project with SQL Server Data Tools (SSDT), the development environment for SQL Server 2012 based on Visual Studio 2010, known in earlier versions as Business Intelligence Development Studio.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_01.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In the data model of this project we will include the tables in the database just created, adding also a measure that sums the values ​​in column SalesAmount.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_02.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;To analyze this model from Excel we will select the menu option SSDT &amp;quot;Model | Analyze in Excel&amp;quot;, or we will click on the button on the toolbar that serves the same purpose.&lt;/p&gt;
&lt;p&gt;I&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_03.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This action will result in opening a new spreadsheet showing the data model in a pivot table which we&amp;#39;ll place the measure &amp;quot;Sum of SalesAmount&amp;quot;, from FactInternetSales table, into the Values block, and the CalendarYear field from DimDate table in block &amp;quot;Row Labels&amp;quot;.&lt;/p&gt;
&lt;p&gt;The result we would need to obtain from this pivot table is the sum of SalesAmount field, that belongs to FactInternetSales table, grouped by sale years, that is, for the year in OrderDateKey field. Since we have DimDate table as catalog dates, if we combine both tables in a SQL query using the appropriate date fields, we&amp;#39;ll get the expected numbers.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_04_5F00_09.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;However, the result obtained in the pivot table is very different, because all the cells show the same value: the sum total of SalesAmount field.This is due to the lack of a relationship between fields and DateKey OrderDateKey from FactInternetSales and DimDate tables respectively, which causes tabular model engine don&amp;#39;t know how to apply the measure &amp;quot;Sum of SalesAmount&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201206/ImportanceRelationshipsSQLServerTabularModels_5F00_05.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Relationships in the tabular model&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In scenarios like the one just described is where we realize the importance that proper establishment of relations between tables in our model, in order to achieve optimal data analysis.&lt;/p&gt;
&lt;p&gt;A tabular model gets, if any, the relationships directly from the data source during execution of the data import wizard.The relationships obtained in this way will name &lt;i&gt;automatic relationships.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;If the model has no relationships or we need additional relationships to existing ones, we can create them using the management relationships window available for this purpose in the development environment of Visual Studio 2010; we&amp;#39;ll call this type &lt;i&gt;manual relationships.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;In our current situation, for the information in model is consistent, we need, as noted above, create a relationship between FactInternetSales and DimDate tables, using OrderDateKey and DateKey fields; so we&amp;#39;ll select the menu opion &amp;quot;Table | Create Relationships&amp;quot; which opens the window where we will make this operation by selecting tables and fields members of the relationship.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_06.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;After relationship creation, we&amp;#39;ll back to the pivot table in Excel that we are using to analyze the model, and then clicking on the Refresh option (Data group in Options tab, contained in the top-level tab &amp;quot;PivotTable Tools&amp;quot;) a new data read will take place, refreshing the pivot table content, and making sales figures by year show correctly.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201206/ImportanceRelationshipsSQLServerTabularModels_5F00_07.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The state of the relationship. Active and inactive relationships&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a data model may happen that a table where we have defined measures, several of his fields relate to a single field in another table that we will use to filter data from the first.When this happens, how can we know what field into measures table is relating to the filter table when we analyze the model for both tables? For those readers experienced OLAP cubes development, the question to ask is: what field of ​​the fact table is relating to the dimension table?&lt;/p&gt;
&lt;p&gt;The answer to this question is found in the relationship status (active or inactive), and the best way to illustrate this concept is through an example.Therefore, we create a new tabular project in SSDT, whose data source is this time the AdventureWorksDW2012 database, importing into the model, as in the previous example, FactInternetSales and DimDate tables, and also defining a measure with the sum of SalesAmount column.&lt;/p&gt;
&lt;p&gt;When we analyze the model in Excel, placing the field CalendarYear in the row labels, the resulting numbers correspond to sales by invoice date.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201206/ImportanceRelationshipsSQLServerTabularModels_5F00_08.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;That will be the same figures we obtained from the SQL query presented in a previous section.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_04_5F00_09.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;At this point is where the reader will surely wonder: &amp;quot;How does the model I want to get the sum of SalesAmount field based on OrderDateKey field, and not on DueDateKey or ShipDateKey, which are also type date? &amp;quot;&lt;/p&gt;
&lt;p&gt;Actually, the model does not know, but merely it uses the active relationship of the model. Let us explain this in more detail:&lt;/p&gt;
&lt;p&gt;If we look at the designer&amp;#39;s model diagram view, we&amp;#39;ll see that from the table FactInternetSales three relationships go to DimDate table.Between the arrows indicating visually the relationships, the one with the continuous line trace corresponds to the active relationship, and therefore, will be used by default when you see the model using the field CalendarYear from DimDate table.Clicking on this relationship, we&amp;#39;ll see its detail in the Visual Studio properties window . Note that the Active property is True.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_10.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;We can also find out the working relationship, and therefore inactive by selecting in Visual Studio the option menu &amp;quot;Table | Manage Relationships&amp;quot;, which will open the relationship management window, where the Active column report us this particular aspect.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_11.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Querying the model through a inactive relationship&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The issue to ask now would be how to question the model, so that it provide us the sum of SalesAmount field, but using any of the other two date fields (ShipDateKey or DueDateKey) that are also related to the DateKey field in DimDate table. In other words, what we need is to alter the context of the currently active default filter.&lt;/p&gt;
&lt;p&gt;The solution is to create a new measure, which will also sum the field SalesAmount, but somehow indicating that the grouping field will be one other than the default.For example, if we want the sales results through ShipDateKey field, we&amp;#39;ll use the following DAXexpression:&lt;/p&gt;
&lt;p&gt;VentasPorFechaEnvio: = CALCULATE (SUM ([SalesAmount]); USERELATIONSHIP (FactInternetSales [ShipDateKey] DimDate [DateKey]))&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To add this measure to the data model, within the area reserved for the measures we will click on an empty cell below the SalesAmount column, and write the previous expression in the formulas / expressions panel.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_12.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Consider this expression by parts: we use the SUM() function since our main goal is to add the SalesAmount field, but when grouping the sum, we want use the ShipDateKey field through its relationship with the DateKey field of DimDate table, so we must explicitly designate that relationship because isn&amp;#39;t active, and this is what we do with USERELATIONSHIP() function.But because of using a relationship that is not active, we need to change the current filter context, what we get using the CALCULATE() function.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201206/ImportanceRelationshipsSQLServerTabularModels_5F00_13.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As we did in previous examples, if we transfer this to a SQL query to check that the values ​​obtained are the same, the sentence would be as illustrated below.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_14.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this paper we have made ​​an introduction to the relationships in tabular models of the new semantic model for Business Intelligence built in SQL Server 2012 2012.This feature represents a cornerstone in building analysis systems using this technology, so we hope this article will help the reader to start in developing their own analysis models using BISM. The worked examples throughout the article are available at this &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201204/RelacionesModelosTabulares.zip"&gt;link&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=205723" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx">BISM</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx">SQL Server 2012</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx">Tabular Model</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx">DAX</category></item><item><title>Generate SQL Server test data from Excel. The transfer to SQL Server (and 2)</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/05/11/generate-sql-server-test-data-from-excel-the-transfer-to-sql-server-and-2.aspx</link><pubDate>Fri, 11 May 2012 19:36:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:204981</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=204981</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=204981</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/05/11/generate-sql-server-test-data-from-excel-the-transfer-to-sql-server-and-2.aspx#comments</comments><description>&lt;p&gt;After data generation in Excel explained in the &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/05/06/generate-sql-server-test-data-from-excel-operations-in-excel-1.aspx"&gt;first part&lt;/a&gt; of the
article, in this second installment we&amp;#39;ll show how to insert that information
into a SQL Server database.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Database creation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After spreadsheet creation, we&amp;#39;ll transfer its contents into a SQL
Server database running the following script from SQL Server Management Studio.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; master&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; Poblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; Poblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosPoblacion (&lt;br /&gt;Fila_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Edad_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;CCAA_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Pais_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Fecha_Alta datetime &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_DatosPoblacion &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Fila_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Sexo (&lt;br /&gt;Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Sexo_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Sexo &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Sexo_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; CCAA (&lt;br /&gt;CCAA_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;CCAA_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_CCAA &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (CCAA_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Pais (&lt;br /&gt;Pais_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Pais_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Paises &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Pais_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As we have seen, in addition to the table that will house the data
generated from Excel, we will also create the catalog tables, which contain
descriptions of some fields of code existing in DatosPoblacion table with which
establish the necessary relationships.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_13.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_13.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Import Excel data from
SQL Server&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To insert data into DatosPoblacion table, we&amp;#39;ll use Transact-SQL&amp;#39;s
OPENROWSET function as follows.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Fila_ID,Edad_ID,Sexo_ID,CCAA_ID,Pais_ID,Fecha_Alta&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\GenerarDatosPoblacion.xlsx&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [Hoja1$]&amp;#39;&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;However, it&amp;#39;s possible we get an error when trying to execute this
insert sentence, which informs us that SQL Server is not configured to query in
this way, called &amp;#39;Ad Hoc Distributed Queries&amp;#39;.&lt;/p&gt;
&lt;p&gt;If we want to check the SQL Server settings, we must run the system
stored procedure sp_configure. However, it is likely that among the options
listed, we do not see the distributed queries configuration. If we are in this
case, we must enable the advanced options display using the following
sentences.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; sp_configure &lt;span style="color:#006080;"&gt;&amp;#39;show advanced options&amp;#39;&lt;/span&gt;,1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RECONFIGURE&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now we see the value of &amp;#39;Ad Hoc Distributed Queries&amp;#39; option by
executing sp_configure.To enable it execute the following.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; sp_configure &lt;span style="color:#006080;"&gt;&amp;#39;Ad Hoc Distributed Queries&amp;#39;&lt;/span&gt;,1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RECONFIGURE&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;When we run sp_configure back, we will already see activated the ability
to run distributed queries.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_14.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_14.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Thus, the previous sentence with OPENROWSET will work properly, filling
the DatosPoblacion table with the content of the GenerarDatosPoblacion.xlsx
file.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_15.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_15.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optimizing data import
from Excel&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;However, at the current point we may face a performance problem, because
if we followed the above steps for creating the Excel file, we have a
spreadsheet with one million rows, which can take about fifteen minutes to load
into SQL Server table. For the sample developed in this article, we have used a virtual machine
with Windows 7 operating system and 1.5 GB RAM, so that the above times may
vary depending on the configuration used for these tests.&lt;/p&gt;
&lt;p&gt;If we want to reduce these load times we may opt an alternative
technique for transferring data which explain below.&lt;/p&gt;
&lt;p&gt;In first place we will open back the file GenerarDatosPoblacion.xlsx,
saving it as &amp;quot;CSV (Comma delimited)&amp;quot; type.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_16.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In this way we&amp;#39;ll get a text file with fields delimited by the semicolon
character. We can see its contents by opening it with Notepad.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_17.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Then we will create a new table in the database with the following
structure.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosPoblacionExcel (&lt;br /&gt;Fila_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Edad_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Sexo_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;CCAA_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Pais_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Anualidad &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Mes &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Dia &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Fecha_Alta &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Into this new table we will import the contents of
GenerarDatosPoblacion.csv, using the Transact-SQL statement BULK INSERT.
Through the FIELDTERMINATOR option, we&amp;#39;ll specify the character used as field
separator, while the option FIRSTROW indicate that the reading of data starts
in the second row of the file, because the first contains the column names.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;BULK&lt;/span&gt; INSERT DatosPoblacionExcel&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;C:\DatosOrigen\GenerarDatosPoblacion.csv&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (FIELDTERMINATOR =&lt;span style="color:#006080;"&gt;&amp;#39;;&amp;#39;&lt;/span&gt;, FIRSTROW=2)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The time consumed by the bulk insert operation in the table
DatosPoblacionExcel be about thirty seconds.&lt;/p&gt;
&lt;p&gt;To finish this process, we will insert in the table DatosPoblacion the
records from DatosPoblacionExcel table, excluding the unnecessary fields, as
shown in the following statement, whose execution will take approximately 15
seconds.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Fila_ID,Edad_ID,Sexo_ID,CCAA_ID,Pais_ID,Fecha_Alta&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; DatosPoblacionExcel&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As we have seen, this inserting data technique, but requires us to
perform an additional step, is a significant gain in time, employing less than
a minute in the transfer of data to the table DatosPoblacion, compared to the
fifteen minutes used by the OPENROWSET function.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Importing the other
catalog tables&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For tables CCAA and Pais, we will use two Excel files containing,
respectively, the official classification of &lt;a href="http://www.madrid.org/iestadis/fijas/clasificaciones/descarga/ccaaprov.zip"&gt;regions&lt;/a&gt;
and &lt;a href="http://www.madrid.org/iestadis/fijas/clasificaciones/descarga/cozonu.zip"&gt;countries&lt;/a&gt; .These files are available in
compressed format on the website of the&amp;nbsp;&lt;span style="text-decoration:underline;"&gt;&lt;a href="http://www.madrid.org/iestadis/index.html"&gt;Madrid Community&amp;nbsp;&lt;/a&gt;&lt;/span&gt;&lt;span style="text-decoration:underline;"&gt;&lt;a href="http://www.madrid.org/iestadis/index.html"&gt;Statistics Institute&lt;/a&gt;&lt;/span&gt;. Once downloaded and unzipped we&amp;#39;ll
run the following SQL statements for import into our database.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; CCAA&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DISTINCT&lt;/span&gt; ccaa, liteccaa&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.Jet.OLEDB.4.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\ccaaprov.xls&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [ccaaprov$]&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Pais&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DISTINCT&lt;/span&gt; isopais,lpaisc&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.Jet.OLEDB.4.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\cozonu.xls&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [cozonu$]&amp;#39;&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Note that depending on the version of Excel file to import, in
OPENROWSET function we&amp;#39;ll use a different provider to
get the data.If the file is for Excel 2007-2010 will use
&amp;#39;Microsoft.ACE.OLEDB.12.0 &amp;#39;, while for earlier versions will be
&amp;quot;Microsoft.Jet.OLEDB.4.0 &amp;#39;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting the country
code in the table DatosPoblacion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A closer look at the records of the Pais table will unveil that Pais_ID
field values ​​are uncorrelated, being also the lowest value 4 and the highest
894.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_18.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This contrasts with existing data in the field of the same name for the
table DatosPoblacion because, although the maximum and minimum value of this
field is also between 4 and 894, we find a lot of records where the field
Pais_ID not correspond to any value in the Pais table.&lt;/p&gt;
&lt;p&gt;To solve this problem we resort to a couple of techniques, of which the
first will be taken from DatosPoblacion table, each Pais_ID field values ​​that
do not exist in the Pais table, adding one until we reach a value which does
exist in the countries catalog table mentioned. We will implement this
process in the SQL Server function below.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;FUNCTION&lt;/span&gt; dbo.ObtenerPais(@nPais_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RETURNS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;COUNT&lt;/span&gt;(*) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Pais &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Pais_ID = @nPais_ID) = 0&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nPais_ID = @nPais_ID + 1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;    &lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RETURN&lt;/span&gt; @nPais_ID&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The update of field Pais_ID in table DatosPoblacion the take out with
the next statement.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;UPDATE&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; Pais_ID = dbo.ObtenerPais(Pais_ID)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Pais_ID &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Pais_ID &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Pais)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The second technique is more direct, as it avoids the use of the search
function of the field Pais_ID in the countries table.What we do here is an
update of the field Pais_ID for the entire table DatosPoblacion, looking in the
Pais table, the value of Pais_ID closest to that exists in the same field in the
table DatosPoblacion.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;UPDATE&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; Pais_ID = (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt; 1 Pais.Pais_ID &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Pais &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Pais.Pais_ID &amp;gt;= DatosPoblacion.Pais_ID &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; Pais.Pais_ID)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In both cases, we get that all the records in the DatosPoblacion table
join correctly with the Pais table through Pais_ID field.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Manual data entry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After the above operations, the only remaining empty table is Sexo, so
we&amp;#39;ll run the following statements, which will create the necessary records.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Hombre&amp;#39;&lt;/span&gt;)&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Mujer&amp;#39;&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Establishing
relationships between tables&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To finish the database creation, we will establish the appropriate
relationships between fields in the table DatosPoblacion and other catalog
tables using the following sentences.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosPoblacion &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CHECK&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;ADD&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; FK_DatosPoblacion_Sexo &lt;span style="color:#0000ff;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;(Sexo_ID) &lt;span style="color:#0000ff;"&gt;REFERENCES&lt;/span&gt; Sexo (Sexo_ID),&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; FK_DatosPoblacion_CCAA &lt;span style="color:#0000ff;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;(CCAA_ID) &lt;span style="color:#0000ff;"&gt;REFERENCES&lt;/span&gt; CCAA (CCAA_ID),&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; FK_DatosPoblacion_Pais &lt;span style="color:#0000ff;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;(Pais_ID) &lt;span style="color:#0000ff;"&gt;REFERENCES&lt;/span&gt; Pais (Pais_ID)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;After this operation we finish this article, which explained the
different parts of a process for generating, from Excel, a considerable amount
of test data that can be used later from SQL Server.We hope you find useful.&lt;/p&gt;
&lt;p&gt;Regards.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=204981" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx">Trucos</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx">SQL Server 2008 R2</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category></item><item><title>Generate SQL Server test data from Excel. Operations in Excel (1)</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/05/06/generate-sql-server-test-data-from-excel-operations-in-excel-1.aspx</link><pubDate>Sun, 06 May 2012 18:09:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:204883</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=204883</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=204883</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/05/06/generate-sql-server-test-data-from-excel-operations-in-excel-1.aspx#comments</comments><description>&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Creating sample data&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;During the application development stages, in most of the time, we are
faced with the need to have at our disposal a set of test data to use in the
different processes that are developing. A similar situation occurs if we are
building an information system based on OLAP data cubes using SQL Server
Analysis Services, because in these cases we will need also a large volume of
data, to perform analysis simulations.&lt;/p&gt;
&lt;p&gt;Suppose we have to generate a database of population data, with a table
containing data of individuals such as age, code region of residence, national
origin, sex, registration date, etc. On the other hand, also need
a series of catalog tables of countries, regions, and other values ​​related to
the fields in the table of individuals.&lt;/p&gt;
&lt;p&gt;Among the full range of utilities, tricks, and more, which exist to
carry out this task, in this article we will use Excel as a tool for generating
the dummy data set for individuals that later we&amp;#39;ll dump in a SQL Server
database, which could be used as a data source for the application or
information system.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Creating data with
Excel&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After starting Excel 2010 (earlier versions may also use), our first
task will be to create a column with the values ​​that will serve to identify
the rows in the table. The simplest way to generate is to introduce a pair
of consecutive numbers in individual cells in a column of the worksheet, select
both cells and drag the fill handle to the last row for which we want to
generate the numbers.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;However, the generation of values ​​using this technique can be somewhat
cumbersome in the case that we must to produce a large number of rows and / or
columns, so that for the creation of data for all columns of the sheet we&amp;#39;ll
use a more flexible yet powerful solution: Excel macros.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Creating a Macro&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To create a macro we will click on the View tab of the Excel ribbon, and
within the Macros group &amp;nbsp;we will click on
the option of the same name, which opens the Macro dialog box, where we&amp;#39;ll write
the macro name: CrearDatosPoblacion.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Clicking the Create button opens the Visual Basic for Applications (VBA)
window editor, so that we can start writing the code of the macro.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Within the procedure body CrearDatosPoblaci&amp;oacute;n, write the following code block, where first, clean up the cells of the spreadsheet where we are
currently positioned. Then ask the user to enter through an InputBox
dialog box, the number of rows to generate. After inserting the column title,
we will introduce the first two values ​​that start the series, which generate
using the method&amp;nbsp; Selection.AutoFill.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;"&gt;&lt;span style="color:#0000ff;"&gt;Option&lt;/span&gt; Explicit&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt; CrearDatosPoblacion()&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nFilaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sCeldaOrigen &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sCeldaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;clean worksheet cells&lt;/span&gt;&lt;br /&gt;Cells.&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.ClearContents&lt;br /&gt;&lt;br /&gt;nFilaDestino = InputBox(&lt;span style="color:#006080;"&gt;&amp;quot;Number of records to generate&amp;quot;&lt;/span&gt;)&lt;br /&gt;nFilaDestino = nFilaDestino + 1&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;fila_id column&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;column caption&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Fila_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;init values of series to generate&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A2&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A3&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;select init values range&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A2:A3&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;fill total range of cells&lt;/span&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;A2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;A&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Selection.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To run the macro will select the menu &amp;quot;Run | Run Sub / UserForm&amp;quot;, or
press the key F5, filling the first column of the sheet with the number of
values ​​indicated in the InputBox.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Before continuing we&amp;#39;ll save our work in VBA or Excel, bearing in mind
that we must do it in a file of type &amp;quot;Excel Macro-Enabled Workbook (.xlsm)&amp;quot;, what
we will be notified by a dialog box in time to save. We will click &amp;quot;No&amp;quot; in that
dialog and save our worksheet in a file named GenerarDatosPoblacion.xlsm.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generating random data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The next column to create correspond to the age of individuals, in it,
need to generate random values ​​within a range of numbers, representing the
maximum and minimum age that a person can have, for example between 0 and 120.&lt;/p&gt;
&lt;p&gt;To create a random value between two numbers in a cell of Excel, we can
use a formula with RANDBETWEEN function, that receives as parameter the above
numbers, returning as a result the number generated.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201205/GenerateSQLServerTestDataFromExcel_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Moving this functionality to the macro that we developed, we will add to
it the next code block, which assign the formula expression RANDBETWEEN
(0,120) to a cell in the second column. We will select that cell, and repeat
the formula over a range of cells using the method ActiveCell.AutoFill.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;age&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;----&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Edad_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;B2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;B&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(0,120)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Running the macro again, we&amp;#39;ll get the new column with the age data.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Our next step is for the column of sex of individuals. Here
we could have used numbers 1 and 2, also generated randomly, to identify male
and female respectively, but let&amp;#39;s get a little this operation, using instead
the letters H and M as values ​​for the column. So the problem now is how to
randomly generate these letters in the cells of the column, since RANDBETWEEN only
receives and returns numerical results.&lt;/p&gt;
&lt;p&gt;The solution is very simple, as it also involves using RANDBETWEEN
function, but combining it with the decision expression IF. We will pass to RANDBETWEEN
the numbers 1 and 2 as parameters, and according to the result obtained, IF
return the letter H or M. Below is the code block for this column, we will add
to the macro.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;sex&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;C1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Sexo_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;C2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;C&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=IF(RANDBETWEEN(1,2)=1,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;H&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;M&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_09.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For the next two columns: code region of residence and country of origin
code, we&amp;#39;ll follow the same mechanics as the column ages, although using
different numerical ranges.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;code region of residence&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;------------------------&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;D1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;CCAA_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;D2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;D&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(1,19)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;country&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;-------&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;E1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Pais_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;E2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;E&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(4,894)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_10.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Our next step is to create the data of an alleged registration date of
individuals in this population system, a task that will make in two phases. First,
we create each part of the date in separate columns.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;date elements:&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;==============&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;year&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;F1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Anualidad&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;F2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;F&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(2008,2010)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;month&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;-----&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;G1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Mes&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;G2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;G&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(1,12)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;day&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;H1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Dia&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;H2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;H&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=IF(RC[-1]=2, RANDBETWEEN(1,28), IF(OR(RC[-1]=4, RC[-1]=6, RC[-1]=9, RC[-1]=11), RANDBETWEEN(1,30), RANDBETWEEN(1,31)))&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As we have seen, the day is the part of the date that requires further
work, as we must be careful to avoid the generation, for example, of a day 31 if
in the month column we have the value 2. We will solve this checking the month
column in first place, and according this we&amp;#39;ll use a different range to
generate the day. So that in the formula we&amp;#39;ll use several IF expressions
combined with RANDBETWEEN functions.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_11.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In the second phase of this operation, we will create a final column in
the spreadsheet with a date in a format understandable to SQL Server, as a
result of the concatenation of the above columns: Anualidad, Mes and Dia. &lt;/p&gt;
&lt;p&gt;It is necessary to take into account when composing the date in this
way, we must add a zero to the month and day when these values ​​are only one
digit.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="background-color:#f4f4f4;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;line-height:12pt;border-style:none;color:black;overflow:visible;padding:0px;width:100%;margin:0em;direction:ltr;text-align:left;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;date composition&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;----------------&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;I1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Fecha_Alta&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;I2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;I&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RC[-3] &amp;amp; IF(LEN(RC[-2])=1,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot; &amp;amp; RC[-2],RC[-2]) &amp;amp; &amp;quot;&lt;/span&gt; &amp;amp; _&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;IF(LEN(RC[-1])=1,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot; &amp;amp; RC[-1],RC[-1]) &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;When we rerun the macro, we&amp;#39;ll get the correctly formatted date in the
last column. This time also establish the number of records to generate in
a million, that way we will test the data creation power of our process.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_12.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To complete operations in Excel we&amp;#39;ll save the file as &amp;quot;Excel
Workbook (*.xlsx)&amp;quot;. Dialog box appears again warning that we couldn&amp;#39;t save
macros in a .xlsx file, which we&amp;#39;ll reply by clicking Yes.&lt;/p&gt;
&lt;p&gt;At this point we conclude the first part of the article, in the second
installment will explain how to transfer the data just generated to SQL Server.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=204883" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx">Trucos</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx">SQL Server 2008 R2</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/VBA/default.aspx">VBA</category></item><item><title>Demographic data generation in SQL Server</title><link>http://geeks.ms/blogs/lmblanco/archive/2012/04/30/demographic-data-generation-in-sql-server.aspx</link><pubDate>Mon, 30 Apr 2012 14:47:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:204754</guid><dc:creator>Luis Miguel Blanco</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/rsscomments.aspx?PostID=204754</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/lmblanco/commentapi.aspx?PostID=204754</wfw:comment><comments>http://geeks.ms/blogs/lmblanco/archive/2012/04/30/demographic-data-generation-in-sql-server.aspx#comments</comments><description>&lt;p&gt;This article addresses the challenge of develop a process to create a database with demographic information, which serves as a starting point for creating a data model in PowerPivot, used in the construction of the population pyramid shown in &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/03/26/population-pyramids-with-powerpivot-preparing-the-data-1.aspx"&gt;Population pyramids with PowerPivot. Preparing the data&lt;/a&gt; and &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/04/01/population-pyramids-with-powerpivot-chart-development-and-2.aspx"&gt;Population pyramids with PowerPivot. Chart development&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unlike the article &amp;quot;Generate SQL Server test data from Excel&amp;quot; (&lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/05/06/generate-sql-server-test-data-from-excel-operations-in-excel-1.aspx"&gt;part 1&lt;/a&gt; and &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/05/11/generate-sql-server-test-data-from-excel-the-transfer-to-sql-server-and-2.aspx"&gt;part 2&lt;/a&gt;) also published in this blog, where we used Excel to generate dummy data population, this time we will work with real data, which represent a larger volume of information to manage with respect the above-mentioned article.&lt;/p&gt;
&lt;p&gt;The current aim is to create a database containing a population table, in which each record represents an individual, with its corresponding age, sex and ​​healthcare area.&lt;/p&gt;
&lt;p&gt;Before proceeding, I want to express my gratitude to Ricard G&amp;egrave;nova Maleras, a demographer specializing in population health analysis, part of the Health Service Reports and Studies (Directorate of Health Promotion and Prevention, DG Primary Care, Health Ministry CM) for their valuable advice in those key demographics for the development of this and the all related population pyramids published in this blog; and the other members of that Service: Jenaro Astray Mochales, Felicitas Dominguez Berj&amp;oacute;n, Mar&amp;iacute;a Dolores Esteban Vasallo and Beatriz Elvira Rodriguez, for their support and assistance in all health concepts about population necessary for the proper focus of this article.&lt;/p&gt;
&lt;p&gt;Last but not least, thanks to Enrique Barcel&amp;oacute;, fellow sufferer in this work of BI, for the interesting times we chatting about matters relating to the development of information systems in general and data cubes in particular, and for sharing his amazing knowledge of OLAP with the rest of the team.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data collection and preparation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are several Web sites belonging to different agencies, where we will find demographic information needed to perform our analysis, organized by criteria such as sex, age, geographic region, etc. Of all these agencies to highlight the relevant &lt;span style="text-decoration:underline;"&gt;&lt;a href="http://esa.un.org/unpd/wpp/Excel-Data/population.htm"&gt;United Nations&lt;/a&gt;&lt;/span&gt; , &lt;a href="http://www.ine.es/inebmenu/mnu_cifraspob.htm"&gt;National Statistical Institute&lt;/a&gt; (Spain), &lt;a href="http://www.madrid.org/iestadis/fijas/estructu/demograficas/padron/estructupc.htm"&gt;Institute of Statistics of the CAM&lt;/a&gt; (Madrid) and &lt;a href="http://www.eclac.org/celade/proyecciones/basedatos_BD.htm"&gt;CELADE&lt;/a&gt; (demographics of Latin America and Caribbean). In all cases, in addition to direct consultation in the website, we have the ability to download information in various formats such as Excel, CSV, etc.&lt;/p&gt;
&lt;p&gt;For the development of the examples in this article we&amp;#39;ll use the registered population data from the Community of Madrid for the year 2010, classified by age, sex and health zoning, effective as of that year, found in the following &lt;a href="http://www.madrid.org/iestadis/fijas/estructu/demograficas/padron/pc10i5z10.htm"&gt;link&lt;/a&gt; (T10Z2_SALUD10) from the website of the Statistical Institute of CAM.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data extraction strategy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Excel file pc10t10z2_salud10.xls obtained from the above link, organizes the data of population around three worksheets containing respectively, the values ​​of total population, men and women.&lt;/p&gt;
&lt;p&gt;Each worksheet has in its first two columns the code and name of the ​​health care area, while the remaining columns contain population figures classified in five-year groups, where each group has a column with the total five-year and several columns representing the detail by simple age of the ages that make up the group.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/DemographicDataGenerationSQLServer_5F00_01.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The data we need extract are, first, the codes and names of health zoning, for which we can use any of the worksheets in the Excel file. Moreover, we have to get the total five-year age group in both sheets: male and female population.&lt;/p&gt;
&lt;p&gt;​​We will bring all these values to a new worksheet in which we copy each combination of health area codes, age group and population type (male / female) in order of steps similar to the following figure.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_02.jpg"&gt;&lt;img border="0" src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_02.jpg" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Here we see an approximation of what would be the resulting spreadsheet.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_03.jpg"&gt;&lt;img border="0" src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_03.jpg" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Using select, copy and paste operations by hand to transfer the needed data to a new sheet can be a cumbersome and heavy task. That is why we propose to use a macro that automates all this work, allowing us to repeat the process as many times as we want, and apply it to other populations whose data is structured the same way.&lt;/p&gt;
&lt;p&gt;To create the macro, on the Excel Ribbon will click on the &amp;quot;Macros&amp;quot; option, belonging to the same name group, located on the &amp;quot;View&amp;quot; tab.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/DemographicDataGenerationSQLServer_5F00_04.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This option is also available on the &amp;quot;Developer&amp;quot; tab, within &amp;quot;Code&amp;quot; group.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/DemographicDataGenerationSQLServer_5F00_05.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In the event that the &amp;quot;Developer&amp;quot; tab is not visible, we will click on the &amp;quot;File&amp;quot; tab, and within this on &amp;quot;Options&amp;quot;. In &amp;quot;Excel Options&amp;quot; window will click &amp;quot;Customize Ribbon&amp;quot; and displaying the list on the right select the item &amp;quot;Main Tabs&amp;quot;. In the panel below the list will check &amp;quot;Developer&amp;quot;, which will make this tab visible in the ribbon.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/DemographicDataGenerationSQLServer_5F00_06.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Regardless the way chosen for its creation, the &amp;quot;Macro&amp;quot; window will appear, we&amp;#39;ll give the name &amp;quot;TraspasarDatosPoblacion&amp;quot; to our macro and click &amp;quot;Create&amp;quot;, which will lead to the VBA (Visual Basic for Applications) editor, where we write the code for the macro.&lt;/p&gt;
&lt;p&gt;We will divide the work to carry out the macro into three parts: data creation for health area code column, age range column, and finally, the columns of numbers of population by sex.&lt;/p&gt;
&lt;p&gt;In the next block of code we can see the instructions responsible of creating a new worksheet, which assign a name and column headings. Later we&amp;#39;ll select the area codes from a source worksheet, which will paste in the new sheet many times as there age ranges.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;Option&lt;/span&gt; Explicit&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Const&lt;/span&gt; RANGOS_COLUMNAS &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt; = 20&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt; TraspasarDatosPoblacion()&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; create new sheet and assign name&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sHojaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sHojaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;DatosBasePoblacion&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; oWorksheet &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; Worksheet&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Set&lt;/span&gt; oWorksheet = Sheets.Add(After:=Sheets(Sheets.Count))&lt;br /&gt;oWorksheet.Name = sHojaDestino&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; assign column titles&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Zona&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Rango_Edad&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;C1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Poblacion_H&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;D1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Poblacion_M&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; back to source data sheet&lt;/span&gt;&lt;br /&gt;Sheets(&lt;span style="color:#006080;"&gt;&amp;quot;Hombres&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; set start and end data rows&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sFilaInicial &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sFilaFinal &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sFilaInicial = &lt;span style="color:#006080;"&gt;&amp;quot;14&amp;quot;&lt;/span&gt;&lt;br /&gt;sFilaFinal = &lt;span style="color:#006080;"&gt;&amp;quot;299&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; calculate number of existing zones&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nCantidadZonas &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;&lt;br /&gt;nCantidadZonas = (&lt;span style="color:#0000ff;"&gt;CInt&lt;/span&gt;(sFilaFinal) - &lt;span style="color:#0000ff;"&gt;CInt&lt;/span&gt;(sFilaInicial))&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; zone codes&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; ---------------&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sColumna &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sColumna = &lt;span style="color:#006080;"&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; select codes, copy to clipboard and paste in a new sheet&lt;/span&gt;&lt;br /&gt;Range(sColumna &amp;amp; sFilaInicial &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna &amp;amp; sFilaFinal).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Copy&lt;br /&gt;Sheets(sHojaDestino).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nContador &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nFilaVacia &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; do paste for each age group&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; nContador = 0 &lt;span style="color:#0000ff;"&gt;To&lt;/span&gt; RANGOS_COLUMNAS&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; obtain next empty row number from column&lt;/span&gt;&lt;br /&gt;    nFilaVacia = FilaVaciaEnColumna(1)&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; place in cell&lt;/span&gt;&lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; paste data&lt;/span&gt;&lt;br /&gt;    ActiveSheet.Paste&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; assign white color background to column&lt;/span&gt;&lt;br /&gt;Columns(&lt;span style="color:#006080;"&gt;&amp;quot;A:A&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Interior.Pattern = xlNone&lt;br /&gt;Selection.Interior.TintAndShade = 0&lt;br /&gt;Selection.Interior.PatternTintAndShade = 0&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Before each assignment of values ​​in cells, we need to know the empty row from which paste the data. For this, we&amp;#39;ll use the auxiliary function &amp;quot;FilaVaciaEnColumna&amp;quot; to iterate the collection of rows in the sheet to find the row containing an empty cell in that column on which we are working.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;Function&lt;/span&gt; FilaVaciaEnColumna(&lt;span style="color:#0000ff;"&gt;ByVal&lt;/span&gt; nPosicionCelda &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vFila &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nFila &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vFila &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; ActiveSheet.Rows&lt;br /&gt;    nFila = vFila.Row&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;If&lt;/span&gt; vFila.Cells(nPosicionCelda).Text = &lt;span style="color:#006080;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Then&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;Exit&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;For&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;FilaVaciaEnColumna = nFila&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Function&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The next phase in creating the macro will be to assign values ​​to the column age ranges. So we&amp;#39;ll create an array containing these values, and to cross it, in each iteration, the current range value will be copied the same number of times than the amount of existing health zones. Note that before assigning values ​​to this column we will apply the text format (property Selection.NumberFormat), since otherwise, the default format may cause some values ​​of the age ranges are interpreted as month-year.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#008000;"&gt;&amp;#39; age ranges&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; --------------&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; aRangosEdad(RANGOS_COLUMNAS) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;aRangosEdad(0) = &lt;span style="color:#006080;"&gt;&amp;quot;0-4&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(1) = &lt;span style="color:#006080;"&gt;&amp;quot;5-9&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(2) = &lt;span style="color:#006080;"&gt;&amp;quot;10-14&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(3) = &lt;span style="color:#006080;"&gt;&amp;quot;15-19&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(4) = &lt;span style="color:#006080;"&gt;&amp;quot;20-24&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(5) = &lt;span style="color:#006080;"&gt;&amp;quot;25-29&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(6) = &lt;span style="color:#006080;"&gt;&amp;quot;30-34&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(7) = &lt;span style="color:#006080;"&gt;&amp;quot;35-39&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(8) = &lt;span style="color:#006080;"&gt;&amp;quot;40-44&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(9) = &lt;span style="color:#006080;"&gt;&amp;quot;45-49&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(10) = &lt;span style="color:#006080;"&gt;&amp;quot;50-54&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(11) = &lt;span style="color:#006080;"&gt;&amp;quot;55-59&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(12) = &lt;span style="color:#006080;"&gt;&amp;quot;60-64&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(13) = &lt;span style="color:#006080;"&gt;&amp;quot;65-69&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(14) = &lt;span style="color:#006080;"&gt;&amp;quot;70-74&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(15) = &lt;span style="color:#006080;"&gt;&amp;quot;75-79&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(16) = &lt;span style="color:#006080;"&gt;&amp;quot;80-84&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(17) = &lt;span style="color:#006080;"&gt;&amp;quot;85-89&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(18) = &lt;span style="color:#006080;"&gt;&amp;quot;90-94&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(19) = &lt;span style="color:#006080;"&gt;&amp;quot;95-99&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(20) = &lt;span style="color:#006080;"&gt;&amp;quot;100+&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; assign format of age column to text&lt;/span&gt;&lt;br /&gt;sColumna = &lt;span style="color:#006080;"&gt;&amp;quot;B&amp;quot;&lt;/span&gt;&lt;br /&gt;Columns(sColumna &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.NumberFormat = &lt;span style="color:#006080;"&gt;&amp;quot;@&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; repeat each value of aRangosEdad array&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; as times as number of existing zones&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vRangoEdad &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vRangoEdad &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; aRangosEdad&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; obtain next empty row number from column&lt;/span&gt;&lt;br /&gt;    nFilaVacia = FilaVaciaEnColumna(2)&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; assign age range value in next two cells down&lt;/span&gt;&lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    ActiveCell.FormulaR1C1 = vRangoEdad&lt;br /&gt;     &lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia + 1)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    ActiveCell.FormulaR1C1 = vRangoEdad&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; set cell range and fill with value of above cells&lt;/span&gt;&lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia) &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia + 1)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    Selection.AutoFill Destination:=Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia) &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia + nCantidadZonas)), Type:=xlFillDefault&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And we end the macro with the assignment of the columns dedicated to the population figures by sex, where this time use two combined arrays containing the column headings that correspond to the five-year total population and population type. When touring both in a nested way, for a certain type of population, we&amp;#39;ll extract their numbers of individuals, assigning them to the destination worksheet.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#008000;"&gt;&amp;#39; population figures by sex&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; ----------------------------&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; aColumnasPoblacion(RANGOS_COLUMNAS) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(0) = &lt;span style="color:#006080;"&gt;&amp;quot;D&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(1) = &lt;span style="color:#006080;"&gt;&amp;quot;J&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(2) = &lt;span style="color:#006080;"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(3) = &lt;span style="color:#006080;"&gt;&amp;quot;V&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(4) = &lt;span style="color:#006080;"&gt;&amp;quot;AB&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(5) = &lt;span style="color:#006080;"&gt;&amp;quot;AH&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(6) = &lt;span style="color:#006080;"&gt;&amp;quot;AN&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(7) = &lt;span style="color:#006080;"&gt;&amp;quot;AT&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(8) = &lt;span style="color:#006080;"&gt;&amp;quot;AZ&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(9) = &lt;span style="color:#006080;"&gt;&amp;quot;BF&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(10) = &lt;span style="color:#006080;"&gt;&amp;quot;BL&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(11) = &lt;span style="color:#006080;"&gt;&amp;quot;BR&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(12) = &lt;span style="color:#006080;"&gt;&amp;quot;BX&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(13) = &lt;span style="color:#006080;"&gt;&amp;quot;CD&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(14) = &lt;span style="color:#006080;"&gt;&amp;quot;CJ&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(15) = &lt;span style="color:#006080;"&gt;&amp;quot;CP&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(16) = &lt;span style="color:#006080;"&gt;&amp;quot;CV&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(17) = &lt;span style="color:#006080;"&gt;&amp;quot;DB&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(18) = &lt;span style="color:#006080;"&gt;&amp;quot;DH&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(19) = &lt;span style="color:#006080;"&gt;&amp;quot;DN&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(20) = &lt;span style="color:#006080;"&gt;&amp;quot;DT&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; aTiposPoblacionColumnas(1) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;aTiposPoblacionColumnas(0) = &lt;span style="color:#006080;"&gt;&amp;quot;Hombres,C,3&amp;quot;&lt;/span&gt;&lt;br /&gt;aTiposPoblacionColumnas(1) = &lt;span style="color:#006080;"&gt;&amp;quot;Mujeres,D,4&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vTipoPoblacionColumna &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sTipoPoblacion &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nPosicionColumna &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vColumnaPoblacion &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; for each population type&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vTipoPoblacionColumna &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; aTiposPoblacionColumnas&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; obtain information of population type:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; sex, target column, numeric position in target column&lt;/span&gt;&lt;br /&gt;    sTipoPoblacion = Split(vTipoPoblacionColumna, &lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;)(0)&lt;br /&gt;    sColumna = Split(vTipoPoblacionColumna, &lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;)(1)&lt;br /&gt;    nPosicionColumna = Split(vTipoPoblacionColumna, &lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;)(2)&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; iterate the columns with population figures&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; and paste in new sheet&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vColumnaPoblacion &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; aColumnasPoblacion&lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; place in sheet with source population data&lt;/span&gt;&lt;br /&gt;        Sheets(sTipoPoblacion).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;     &lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; select and copy cells&lt;/span&gt;&lt;br /&gt;        Range(vColumnaPoblacion &amp;amp; sFilaInicial &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; vColumnaPoblacion &amp;amp; sFilaFinal).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;        Selection.Copy&lt;br /&gt;         &lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; place in target sheet&lt;/span&gt;&lt;br /&gt;        Sheets(sHojaDestino).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; obtain next empty row, place in cell and paste data&lt;/span&gt;&lt;br /&gt;        nFilaVacia = FilaVaciaEnColumna(nPosicionColumna)&lt;br /&gt;        Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;        ActiveSheet.Paste&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; change column style to display cell borders&lt;/span&gt;&lt;br /&gt;Columns(&lt;span style="color:#006080;"&gt;&amp;quot;C:D&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Style = &lt;span style="color:#006080;"&gt;&amp;quot;Normal&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then create a new macro with the name &amp;quot;TraspasarDatosZonificacion&amp;quot; whereby we&amp;#39;ll move to a new worksheet codes and names of the healthcare areas. These data will be used to load a table in the database we&amp;#39;ll create later.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt; TraspasarDatosZonificacion()&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; create new sheet and assign name&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sHojaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sHojaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;DatosZonificacion&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; oWorksheet &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; Worksheet&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Set&lt;/span&gt; oWorksheet = Sheets.Add(After:=Sheets(Sheets.Count))&lt;br /&gt;oWorksheet.Name = sHojaDestino&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; set column titles&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Zona_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Zona_DS&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; back to data sheet&lt;/span&gt;&lt;br /&gt;Sheets(&lt;span style="color:#006080;"&gt;&amp;quot;Hombres&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; copy zone codes and names to clipboard&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A14:B299&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Copy&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; back to target sheet and paste data&lt;/span&gt;&lt;br /&gt;Sheets(sHojaDestino).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A2&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveSheet.Paste&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; remove cell background color&lt;/span&gt;&lt;br /&gt;Columns(&lt;span style="color:#006080;"&gt;&amp;quot;A:B&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Interior.Pattern = xlNone&lt;br /&gt;Selection.Interior.TintAndShade = 0&lt;br /&gt;Selection.Interior.PatternTintAndShade = 0&lt;br /&gt; &lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When we copy the codes and names of the health zones to new sheets within the Excel file, the color configuration of the cells corresponding to these values is copied too. To achieve white background color in these cells, we use the following lines of code.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;Selection.Interior.TintAndShade = 0&lt;br /&gt;Selection.Interior.PatternTintAndShade = 0&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;But if our version of Excel is prior to 2007 these lines will fail at runtime, so we must comment them to avoid being executed.&lt;/p&gt;
&lt;p&gt;Finally, from the macro management window, we&amp;#39;ll select each one and click on &amp;quot;Run&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img style="max-width:550px;" border="0" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/DemographicDataGenerationSQLServer_5F00_07.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As a result we will obtain two new sheets with the data generated by the macros.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_08.jpg"&gt;&lt;img border="0" src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_08.jpg" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Database creation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our next step is to create the database PiramidePoblacion, to accommodate the information we have just prepared in Excel. The following code block shows the Transact-SQL script that will be executed in our SQL Server instance (in this article we have used SQL Server 2008 R2).&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; PiramidePoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; PiramidePoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosBasePoblacion&lt;br /&gt;(&lt;br /&gt;    Fila_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Zona &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Rango_Edad &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Poblacion_H &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Poblacion_M &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Poblacion&lt;br /&gt;(&lt;br /&gt;    Fila_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Zona_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Edad_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Poblacion &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Fila_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Zona&lt;br /&gt;(&lt;br /&gt;    Zona_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Zona_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(30) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Zona &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Zona_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Edad&lt;br /&gt;(&lt;br /&gt;    Edad_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Edad_Grupo &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Edad &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Edad_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Sexo&lt;br /&gt;(&lt;br /&gt;    Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Sexo_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Sexo &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Sexo_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;The table Poblacion will contain the main data of our population, while tables Zona, Edad and Sexo contain catalog information (code / descriptor).&lt;/p&gt;
&lt;p&gt;Surely, in the script we will have noticed the lack of foreign keys between Poblacion table and the rest. This is an intentional forgetting that we&amp;#39;ll fix in the articles &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/03/26/population-pyramids-with-powerpivot-preparing-the-data-1.aspx"&gt;Population pyramids with PowerPivot. Preparing the data&lt;/a&gt; and &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/04/01/population-pyramids-with-powerpivot-chart-development-and-2.aspx"&gt;Population pyramids with PowerPivot. Chart development&lt;/a&gt;, where we demonstrate how using PowerPivot we can also create relationships between tables in the model.&lt;/p&gt;
&lt;p&gt;After running the script, the first action that will take place in the new database will be transfer data from sheet DatosBasePoblacion of file pc10t10z2_salud10.xls into the table of the same name, using the following statement.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; DatosBasePoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; * &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\pc10t10z2_salud10.xls&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [DatosBasePoblacion$]&amp;#39;&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Generating population records in the database&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The purpose of the process that we are doing so far is to generate, for table Poblacion, a number of records that represent the population with which we work, and that will equal the sum of columns Poblacion_H and Poblacion_M from table DatosBasePoblacion.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_09.jpg"&gt;&lt;img border="0" src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_09.jpg" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For this volume of data, using a loop to create one by one the records is totally unfeasible due to time and performance reasons, so we must find an alternative technique that allows us to work using sets of results, to create the necessary number of records, using a small number of operations.&lt;/p&gt;
&lt;p&gt;The technique that we will opt is shown in the book &lt;a href="http://www.microsoft.com/learning/en/us/book.aspx?ID=12804&amp;amp;locale=en-us"&gt;Microsoft SQL Server 2008: T-SQL Querying&lt;/a&gt; , by &lt;a href="http://tsql.solidq.com/index.htm"&gt;Itzik Ben-Gan&lt;/a&gt; and other great names in SQL Server: Lubor Kollar, Dejan Sarka and Steve Kass; and is use several &amp;quot;Common Table Expressions&amp;quot; or CTE nested, through which generate a result set of appropiate size, that we will combine with an INSERT INTO statement, to add to Poblacion table a determined number of records. All this will include in the following stored procedure.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PROCEDURE&lt;/span&gt; GenerarRegistrosPoblacion&lt;br /&gt;@nZona_ID &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;,&lt;br /&gt;@sRango_Edad &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10),&lt;br /&gt;@sSexo_ID &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1),&lt;br /&gt;@nPoblacion &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nEdad_ID &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; =&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;CASE&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; CHARINDEX(&lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;,@sRango_Edad) = 0 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; 100&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; CHARINDEX(&lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;,@sRango_Edad) = 2 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CAST&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;LEFT&lt;/span&gt;(@sRango_Edad,1) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; CHARINDEX(&lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;,@sRango_Edad) = 3 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CAST&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;LEFT&lt;/span&gt;(@sRango_Edad,2) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt;&lt;br /&gt;Numeros0 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;UNION&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;ALL&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1),&lt;br /&gt;Numeros1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros0 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros0 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros5 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;NumerosTotal &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; ROW_NUMBER() &lt;span style="color:#0000ff;"&gt;OVER&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 0)) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; NumeroFila &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros5)&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Poblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @nZona_ID, @nEdad_ID, @sSexo_ID &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; NumerosTotal&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; NumeroFila &amp;lt;= @nPoblacion;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;GO&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then write a script which will cross the DatosBasePoblacion table, and each of their records will take the value of Poblacion_H and Poblacion_M fields, inserting in Poblacion table, by executing the stored procedure GenerarRegistrosPoblacion, a number of rows equal to value of the aforementioned fields.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; = 1;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nDatosBaseFilaFinal &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; = (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;MAX&lt;/span&gt;(Fila_ID) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; DatosBasePoblacion);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nZona &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sRango_Edad &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nPoblacion_H &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nPoblacion_M &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (@nContador &amp;lt;= @nDatosBaseFilaFinal)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @nZona = Zona,&lt;br /&gt;        @sRango_Edad = Rango_Edad,&lt;br /&gt;        @nPoblacion_H = Poblacion_H, &lt;br /&gt;        @nPoblacion_M = Poblacion_M&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; DatosBasePiramidePoblacion&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Fila_ID = @nContador;&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; GenerarRegistrosPoblacion @nZona, @sRango_Edad, &lt;span style="color:#006080;"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;,@nPoblacion_H&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; GenerarRegistrosPoblacion @nZona, @sRango_Edad, &lt;span style="color:#006080;"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;,@nPoblacion_M&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nContador += 1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The time spent in the execution of this script was 1 minute and 37 seconds in a virtual machine equipped with a Core 2 Duo CPU and 1.5 GB of RAM, which represents excellent performance given the large number of records added to Poblacion table.&lt;/p&gt;
&lt;p&gt;We ended the preparing database operations with the statements used to add data in tables that serve as catalogs for the table Poblacion. As we see below, for the Zona table we also get the records from pc10t10z2_salud10.xls file.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;" id="codeSnippet"&gt;--&lt;span style="color:#008000;"&gt;////&lt;/span&gt;&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Zona&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; * &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\pc10t10z2_salud10.xls&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [DatosZonificacion$]&amp;#39;&lt;/span&gt;)&lt;br /&gt; &lt;br /&gt;--&lt;span style="color:#008000;"&gt;////&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; = 0;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (@nContador &amp;lt;= 120)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;    INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Edad&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @nContador,&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;CASE&lt;/span&gt; &lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 0 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 4 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;000-004&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 5 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 9 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;005-009&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 10 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 14 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;010-014&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 15 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 19 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;015-019&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 20 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 24 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;020-024&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 25 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 29 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;025-029&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 30 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 34 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;030-034&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 35 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 39 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;035-039&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 40 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 44 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;040-044&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 45 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 49 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;045-049&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 50 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 54 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;050-054&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 55 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 59 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;055-059&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 60 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 64 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;060-064&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 65 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 69 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;065-069&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 70 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 74 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;070-074&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 75 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 79 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;075-079&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 80 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 84 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;080-084&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 85 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 89 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;085-089&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 90 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 94 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;090-094&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 95 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 99 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;095-099&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &amp;gt;= 100 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;100+&amp;#39;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nContador += 1;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;--&lt;span style="color:#008000;"&gt;////&lt;/span&gt;&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Hombre&amp;#39;&lt;/span&gt;)&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Mujer&amp;#39;&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Data loading completed&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At this point we conclude the process of creation and loading of demographic information in our database. In the articles pointed out at the beginning, we will use this database as a starting point for the construction of population pyramids with PowerPivot.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=204754" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx">SQL Server 2008 R2</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx">Excel</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx">Business Intelligence</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx">Data Warehouse</category><category domain="http://geeks.ms/blogs/lmblanco/archive/tags/VBA/default.aspx">VBA</category></item></channel></rss>