<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang=""><title type="html">El aprendiz de brujo </title><subtitle type="html">El blog de Luis Miguel Blanco con hechizos, conjuros y sortilegios varios sobre la plataforma .NET
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;img src="http://geeks.ms/blogs/lmblanco/ImgEnl/HatWand.jpg" style="border-style:none;vertical-align:middle;" alt="" /&gt;
</subtitle><id>http://geeks.ms/blogs/lmblanco/atom.aspx</id><link rel="alternate" type="text/html" href="http://geeks.ms/blogs/lmblanco/default.aspx" /><link rel="self" type="application/atom+xml" href="http://geeks.ms/blogs/lmblanco/atom.aspx" /><generator uri="http://communityserver.org" version="4.1.31106.3070">Community Server</generator><updated>2011-01-26T18:57:00Z</updated><entry><title>Generate SQL Server test data from Excel. The transfer to SQL Server (and 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/05/11/generate-sql-server-test-data-from-excel-the-transfer-to-sql-server-and-2.aspx" /><id>/blogs/lmblanco/archive/2012/05/11/generate-sql-server-test-data-from-excel-the-transfer-to-sql-server-and-2.aspx</id><published>2012-05-11T19:36:00Z</published><updated>2012-05-11T19:36:00Z</updated><content type="html">&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;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /></entry><entry><title>Generate SQL Server test data from Excel. Operations in Excel (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/05/06/generate-sql-server-test-data-from-excel-operations-in-excel-1.aspx" /><id>/blogs/lmblanco/archive/2012/05/06/generate-sql-server-test-data-from-excel-operations-in-excel-1.aspx</id><published>2012-05-06T18:09:00Z</published><updated>2012-05-06T18:09:00Z</updated><content type="html">&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;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="VBA" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/VBA/default.aspx" /></entry><entry><title>Demographic data generation in SQL Server</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/04/30/demographic-data-generation-in-sql-server.aspx" /><id>/blogs/lmblanco/archive/2012/04/30/demographic-data-generation-in-sql-server.aspx</id><published>2012-04-30T14:47:00Z</published><updated>2012-04-30T14:47:00Z</updated><content type="html">&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;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="VBA" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/VBA/default.aspx" /></entry><entry><title>La importancia de las relaciones en los modelos tabulares de SQL Server 2012</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/04/15/la-importancia-de-las-relaciones-en-los-modelos-tabulares-de-sql-server-2012.aspx" /><id>/blogs/lmblanco/archive/2012/04/15/la-importancia-de-las-relaciones-en-los-modelos-tabulares-de-sql-server-2012.aspx</id><published>2012-04-15T14:15:00Z</published><updated>2012-04-15T14:15:00Z</updated><content type="html">&lt;p&gt;Una caracter&amp;iacute;stica esencial de los modelos de datos
tabulares pertenecientes a BISM (Business Intelligence Semantic Model), el nuevo
paradigma de desarrollo BI incorporado en SQL Server 2012, lo constituyen las
relaciones entre las tablas integrantes de un determinado modelo, ya que sin
ellas resultar&amp;iacute;a imposible realizar un adecuado an&amp;aacute;lisis de la informaci&amp;oacute;n
contenida en el mismo.&lt;/p&gt;
&lt;p&gt;Pongamos como ejemplo que tenemos una base de datos
con el nombre AdvWksDW, creada a partir de algunas de las tablas de la base de
datos &lt;a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"&gt;AdventureWorksDW2012&lt;/a&gt;,
pero sin las correspondientes relaciones entre las mismas. El siguiente bloque
de c&amp;oacute;digo muestra las sentencias SQL necesarias para su creaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&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 * INTO FactInternetSales FROM AdventureWorksDW2012.dbo.FactInternetSales&lt;/p&gt;
&lt;p&gt;GO&lt;/p&gt;
&lt;p&gt;SELECT * INTO DimDate FROM AdventureWorksDW2012.dbo.DimDate&lt;/p&gt;
&lt;p&gt;GO&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para aquellos lectores m&amp;aacute;s familiarizados con el
trabajo con modelos de an&amp;aacute;lisis multidimensional, si tuvi&amp;eacute;ramos que
desarrollar un cubo OLAP empleando esta base de datos, la tabla FactInternetSales
representar&amp;iacute;a a la &lt;i&gt;tabla de hechos&lt;/i&gt;,
ya que contiene las columnas a partir de las cuales podemos obtener las medidas
o resultados num&amp;eacute;ricos a analizar; mientras que la tabla DimDate representar&amp;iacute;a
a una &lt;i&gt;tabla de dimensi&amp;oacute;n&lt;/i&gt;, empleada para
filtrar la informaci&amp;oacute;n por las fechas existentes en el modelo.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n crearemos un proyecto de an&amp;aacute;lisis de
tipo tabular con SQL Server Data Tools (SSDT); el entorno de desarrollo para
SQL Server 2012 basado en Visual Studio 2010, conocido en anteriores versiones
como Business Intelligence Development Studio.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;En el modelo de datos de este proyecto incluiremos las
tablas de la base de datos que acabamos de crear, a&amp;ntilde;adiendo tambi&amp;eacute;n una medida que
sume los valores de la columna SalesAmount.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;Para analizar este modelo desde Excel
seleccionaremos la opci&amp;oacute;n de men&amp;uacute; de SSDT &amp;quot;Model | Analyze in Excel&amp;quot;, o bien
haremos clic en el bot&amp;oacute;n de la barra de herramientas que desempe&amp;ntilde;a el mismo
prop&amp;oacute;sito.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;Esta acci&amp;oacute;n tendr&amp;aacute; como resultado la apertura de una
nueva hoja de c&amp;aacute;lculo que mostrar&amp;aacute; el modelo de datos en una tabla din&amp;aacute;mica,
dentro de la cual situaremos la medida &amp;quot;Sum of SalesAmount&amp;quot; de la tabla
FactInternetSales en el bloque Valores, y el campo CalendarYear de la tabla
DimDate en el bloque &amp;quot;Etiquetas de fila&amp;quot;.&lt;/p&gt;
&lt;p&gt;El resultado que necesitar&amp;iacute;amos obtener de esta tabla
din&amp;aacute;mica ser&amp;iacute;a la suma del campo SalesAmount, perteneciente a la tabla
FactInternetSales, agrupada por los a&amp;ntilde;os de venta, es decir, por el a&amp;ntilde;o del
campo OrderDateKey. Puesto que contamos con la tabla DimDate como cat&amp;aacute;logo de
fechas, si combinamos en una consulta SQL ambas tablas por los campos de fecha adecuados,
obtendr&amp;iacute;amos las cifras esperadas.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_04_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_04_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Sin embargo el resultado obtenido en la tabla
din&amp;aacute;mica es muy distinto, ya que todas sus celdas muestran el mismo valor: el total
de la suma del campo SalesAmount. Esto es debido a la inexistencia de una relaci&amp;oacute;n
entre los campos OrderDateKey y DateKey de las tablas FactInternetSales y
DimDate respectivamente, lo cual produce que el motor del modelo tabular no
sepa c&amp;oacute;mo aplicar la medida &amp;quot;Sum of SalesAmount&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;strong&gt;Relaciones
en el modelo tabular&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;En escenarios como el que acabamos de describir es donde
nos damos cuenta de la importancia que cobra un adecuado establecimiento de
relaciones entre las tablas de nuestro modelo, a fin de conseguir un &amp;oacute;ptimo
an&amp;aacute;lisis de la informaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Un modelo tabular obtiene, en el caso de que
existan, las relaciones directamente de la fuente de datos origen durante la
ejecuci&amp;oacute;n del asistente de importaci&amp;oacute;n de datos. A las relaciones obtenidas de
esta forma las denominaremos &lt;i&gt;relaciones
autom&amp;aacute;ticas&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Si el modelo carece de relaciones, o bien
necesitamos relaciones adicionales a las ya existentes, podemos crearlas
mediante la ventana de administraci&amp;oacute;n disponible a tal efecto en el entorno de
desarrollo de Visual Studio 2010; llamaremos a este tipo &lt;i&gt;relaciones manuales&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;En nuestra situaci&amp;oacute;n actual, para que la informaci&amp;oacute;n
del modelo resulte coherente, necesitamos, como hemos indicado antes, crear una
relaci&amp;oacute;n entre las tablas FactInternetSales y DimDate, por los campos OrderDateKey
y DateKey; para ello seleccionaremos la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Table | Create
Relationships&amp;quot;, que abrir&amp;aacute; la ventana en la que realizaremos dicha operaci&amp;oacute;n,
seleccionando las tablas y campos integrantes de la relaci&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.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;Una vez creada la relaci&amp;oacute;n volveremos a la tabla
din&amp;aacute;mica de Excel en la que estamos analizando el modelo, y despu&amp;eacute;s de hacer
clic en la opci&amp;oacute;n Actualizar (grupo Datos de la pesta&amp;ntilde;a Opciones, contenida en
la pesta&amp;ntilde;a de nivel superior &amp;quot;Herramientas de tabla din&amp;aacute;mica&amp;quot;) se producir&amp;aacute; una
nueva lectura de los datos del modelo por parte de la tabla din&amp;aacute;mica,
refrescando su contenido, y haciendo que las cifras de ventas por a&amp;ntilde;o se
muestren ya correctamente.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;strong&gt;El estado
de la relaci&amp;oacute;n. Relaciones activas e inactivas&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;En un mod&lt;a name="mk1"&gt;&lt;/a&gt;elo de datos puede suceder
que una tabla en la que hemos definido medidas, varios de sus campos se
relacionen con un mismo campo de otra tabla que vamos a utilizar para filtrar
los datos de la primera. Cuando esto ocurre, &amp;iquest;c&amp;oacute;mo podemos saber qu&amp;eacute; campo de
la tabla de medidas se est&amp;aacute; relacionando con la tabla de filtro al analizar el
modelo por ambas tablas? Para aquellos lectores con experiencia en el
desarrollo de cubos OLAP, la pregunta a formular ser&amp;iacute;a: &amp;iquest;qu&amp;eacute; campo de la tabla
de hechos se est&amp;aacute; relacionando con la tabla de dimensi&amp;oacute;n?&lt;/p&gt;
&lt;p&gt;La respuesta a esta pregunta la hallamos en el
estado de la relaci&amp;oacute;n (activa o inactiva), y la mejor manera de ilustrar este
concepto es a trav&amp;eacute;s de un ejemplo. Por consiguiente, vamos a crear un nuevo
proyecto tabular en SSDT, cuya fuente de datos sea esta vez la base de datos
AdventureWorksDW2012, importando en el modelo, al igual que en el ejemplo
anterior, las tablas FactInternetSales y DimDate; y definiendo igualmente una
medida con la suma de la columna SalesAmount.&lt;/p&gt;
&lt;p&gt;Al analizar el modelo en Excel, situando el campo
CalendarYear en las etiquetas de fila, los n&amp;uacute;meros resultantes corresponder&amp;aacute;n a
las ventas realizadas por fecha de factura.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;Que ser&amp;aacute;n las mismas cifras que obten&amp;iacute;amos de la
consulta SQL presentada en un apartado anterior.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_04_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_5F00_04_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Llegados a este punto es donde el lector se
preguntar&amp;aacute; con toda seguridad: &amp;quot;&amp;iquest;Y c&amp;oacute;mo sabe el modelo que yo quiero obtener la
suma del campo SalesAmount en base al campo OrderDateKey, y no en base a
DueDateKey o ShipDateKey, que tambi&amp;eacute;n son de tipo fecha?&amp;quot;&lt;/p&gt;
&lt;p&gt;Realmente, el modelo no lo sabe, sino que se limita
a utilizar la relaci&amp;oacute;n activa del modelo. Expliquemos esto con mayor detalle:&lt;/p&gt;
&lt;p&gt;Si observamos el dise&amp;ntilde;ador del modelo en vista de
diagrama, veremos que desde la tabla FactInternetSales parten tres relaciones
hacia la tabla DimDate. De las flechas que indican visualmente las relaciones,
la que tiene el trazo de l&amp;iacute;nea continuo corresponde a la relaci&amp;oacute;n activa, y por
lo tanto, ser&amp;aacute; la que se utilizar&amp;aacute; de forma predeterminada cuando se consulte
el modelo empleando el campo CalendarYear de la tabla DimDate. Al hacer clic en
dicha relaci&amp;oacute;n, la ventana de propiedades del entorno de desarrollo de Visual
Studio mostrar&amp;aacute; el detalle de la misma. N&amp;oacute;tese que la propiedad Active tiene el
valor True.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;Tambi&amp;eacute;n podemos averiguar cu&amp;aacute;l es la relaci&amp;oacute;n activa,
y por ende, las inactivas, seleccionando en Visual Studio la opci&amp;oacute;n de men&amp;uacute;
&amp;quot;Table | Manage Relationships&amp;quot;, que abrir&amp;aacute; la ventana de administraci&amp;oacute;n de las
relaciones del modelo, donde la &amp;nbsp;columna
Active nos informar&amp;aacute; de este aspecto en particular.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;&lt;strong&gt;Consultando
el modelo a trav&amp;eacute;s de una relaci&amp;oacute;n inactiva&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;La cuesti&amp;oacute;n a plantear ahora ser&amp;iacute;a
c&amp;oacute;mo podr&amp;iacute;amos interrogar al modelo, de forma que nos proporcionara la suma del campo SalesAmount, pero utilizando alguno de los otros
dos campos de fecha (DueDateKey o ShipDateKey) que tambi&amp;eacute;n est&amp;aacute;n relacionados con
el campo DateKey de la tabla DimDate. Dicho con otras palabras, lo que
necesitamos es alterar el contexto de filtro predeterminado actualmente activo.&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n
pasa por crear una nueva medida, que tambi&amp;eacute;n sume el campo SalesAmount, pero
indicando de alguna manera que el campo de agrupaci&amp;oacute;n va a ser uno distinto del
predeterminado. Por ejemplo, si queremos obtener los resultados de ventas por
el campo ShipDateKey, usaremos la siguiente expresi&amp;oacute;n DAX:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;VentasPorFechaEnvio:=CALCULATE( SUM([SalesAmount]) ;
USERELATIONSHIP(FactInternetSales[ShipDateKey]; DimDate[DateKey]) )&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para a&amp;ntilde;adir
esta medida al modelo de datos, dentro del &amp;aacute;rea reservada a las medidas haremos
clic en una celda vac&amp;iacute;a debajo de la columna SalesAmount, y escribiremos la
anterior expresi&amp;oacute;n en el panel de introducci&amp;oacute;n de f&amp;oacute;rmulas/expresiones.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;Analicemos
esta expresi&amp;oacute;n por partes: debemos emplear la funci&amp;oacute;n SUM(), ya que nuestro
objetivo principal es sumar el campo SalesAmount, pero como queremos que al
agrupar la suma, se utilice el campo ShipDateKey, mediante la relaci&amp;oacute;n de &amp;eacute;ste
con el campo DateKey de la tabla DimDate, tenemos que especificar
expl&amp;iacute;citamente dicha relaci&amp;oacute;n porque no es la activa, y esto es lo que hacemos
con la funci&amp;oacute;n USERELATIONSHIP(). Ahora bien, precisamente por el hecho de
utilizar una relaci&amp;oacute;n que no es la activa, necesitamos alterar el contexto de
filtro actual, lo que conseguimos usando la funci&amp;oacute;n CALCULATE().&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;Como hemos
hecho en ejemplos anteriores, si trasladamos esta situaci&amp;oacute;n a una consulta SQL,
para comprobar que los valores obtenidos son los mismos, la sentencia quedar&amp;iacute;a
tal y como vemos 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.201204/ImportanciaRelacionesModelosTabularesSQLServer_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;strong&gt;Conclusiones&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;En el presente art&amp;iacute;culo hemos realizado una introducci&amp;oacute;n
a las relaciones en los modelos tabulares del nuevo modelo sem&amp;aacute;ntico para
Business Intelligence incorporado a SQL Server 2012. Dicha caracter&amp;iacute;stica
representa una pieza fundamental en la construcci&amp;oacute;n de sistemas de an&amp;aacute;lisis
empleando esta tecnolog&amp;iacute;a, por lo que confiamos en que este art&amp;iacute;culo sirva de
ayuda al lector para iniciarse en el desarrollo de sus propios modelos de
an&amp;aacute;lisis utilizando BISM. Los ejemplos elaborados a lo largo del art&amp;iacute;culo est&amp;aacute;n
disponibles en este &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201204/RelacionesModelosTabulares.zip"&gt;enlace&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=204467" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="BISM" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/BISM/default.aspx" /><category term="SQL Server 2012" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2012/default.aspx" /><category term="Tabular Model" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Tabular+Model/default.aspx" /><category term="DAX" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx" /></entry><entry><title>Population pyramids with PowerPivot. Chart development (and 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/04/01/population-pyramids-with-powerpivot-chart-development-and-2.aspx" /><id>/blogs/lmblanco/archive/2012/04/01/population-pyramids-with-powerpivot-chart-development-and-2.aspx</id><published>2012-04-01T11:06:00Z</published><updated>2012-04-01T11:06:00Z</updated><content type="html">&lt;p&gt;In the &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/03/26/population-pyramids-with-powerpivot-preparing-the-data-1.aspx"&gt;first part&lt;/a&gt; of this article we developed a data model in PowerPivot representing population figures by age and sex. In this second installment will shape these figures on a chart shaped population pyramid.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pyramid chart. First approach&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In its current state, the pivot table already have enough information (figures by population, age and sex) to try to create a chart that represents a population pyramid, but we advance the reader that in this first approach we will not get the desired effect.&lt;/p&gt;
&lt;p&gt;Positioned in the pivot table, from the Excel ribbon, select the option &amp;quot;PivotChart&amp;quot; belonging to &amp;quot;Tools&amp;quot; group from &amp;quot;Options&amp;quot; tab, which in turn is contained in the top-level tab &amp;quot;PivotTable Tools&amp;quot;.&lt;/p&gt;
&lt;p&gt;This selection opens &amp;quot;Insert Chart&amp;quot; window, which contains all available chart types. Here we will realize that there is no specific template for creating a pyramid chart, therefore, of all bid at our disposal we choose, within &amp;quot;Bar&amp;quot; category, the &amp;quot;Clustered Bar&amp;quot; type, which as we shall see later, it will be the best adapted to the result we want achieve.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;Accepting this window, the chart will be created from the PivotTable data, and as we anticipated, the result won&amp;#39;t look like the image presented in the first part of the article.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;However, the main difference lies in the orientation of the men bar population, which should be left. All other aspects are basically visual configuration issues, which explain how to solve in short.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solving the trajectory of the population bars&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Focusing on the male population&amp;nbsp;bar, the solution for achieve to draw itself in the opposite direction to the current, is to put in negative the values ​​of the cells in the pivot table for this segment of the population.&lt;/p&gt;
&lt;p&gt;If we were in a simple spreadsheet with no connection to PowerPivot, the solution is as simple as editing the cells in column Hombre, changing their values to negative, but in this scenario data is being obtained from the PowerPivot data model, so that it&amp;#39;s not possible directly edit the values ​​in the PivotTable.&lt;/p&gt;
&lt;p&gt;To solve this kind of problems we have to resort to the creation of columns and / or calculated measures, which through DAX expressions provide the results we need. In the transition to negative the values ​​of the Hombre column, we will open the PowerPivot window, and placing ourselves in the first available empty column in the Poblacion table, write the following expression in the formula bar:&lt;/p&gt;
&lt;p&gt;=IF([Sexo_ID] = &amp;quot;M&amp;quot;, 1, -1)&lt;/p&gt;
&lt;p&gt;We just created a calculated column that will be evaluated for each row of the Poblacion table, checking if Sexo_ID field value is equal to the letter &amp;quot;M&amp;quot; (Mujer), if so, the column value in that row will be 1, otherwise, when the field contains &amp;quot;H&amp;quot; (Hombre),&amp;nbsp;the returned value will be -1.&lt;/p&gt;
&lt;p&gt;Then we double-click its header to assign Sexo_Codigo as the column&amp;#39;s&amp;nbsp;name it. We can also give name by right clicking on the header and choosing &amp;quot;Rename Column&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;Turning again to the Excel window, we&amp;#39;ll remove the chart we created in the worksheet and uncheck the RecuentoPoblacion measure, leaving empty the area of ​​the PivotTable values.&lt;/p&gt;
&lt;p&gt;The next step will be to create a new measure named SumaPoblacion, based on the following DAX expression:&lt;/p&gt;
&lt;p&gt;=SUM([Sexo_Codigo])&lt;/p&gt;
&lt;p&gt;By applying this measure to the PivotTable, the SUM function takes the sum of column values ​​passed as parameter, so the population figures of men now appear negative. This means that when re-creating the chart in the manner explained above, the indicator bars of the population values by sex are now drawn in opposite directions. As an additional feature, on &amp;quot;PivotTable Tools&amp;quot; tab, into &amp;quot;Design&amp;quot; tab, at the &amp;quot;Layout&amp;quot; group, we&amp;#39;ll drop &amp;quot;Grand Totals&amp;quot;, selecting &amp;quot;On for Columns Only&amp;quot;, that hides the row totals column, because its presence in this context is irrelevant.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;&lt;strong&gt;Visual configuration of population bars&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although the chart bars are now shown with the effect we wanted, it would be desirable a few tweaks in its visual appearance to improve the presentation quality.&lt;/p&gt;
&lt;p&gt;First we right click on the age ranges labels, selecting &amp;quot;Format axis&amp;quot;. In the window of the same name, under &amp;quot;Axis Options&amp;quot;, assign the value &amp;quot;Low&amp;quot; to &amp;quot;Axis Labels&amp;quot; property, which align the labels column to the left of the chart.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;Then we right click on any of the bars in the graph, choosing &amp;quot;Format Data Series&amp;quot;. In the configuration series window, into &amp;quot;Series Options,&amp;quot; on property &amp;quot;Series Overlap&amp;quot; will move the position marker to the right end position (fully overlapped), while in property &amp;quot;Gap Width&amp;quot; will move the position marker to the left end (no gap at all). In this way we will accomplish the bars increase their thickness and eliminate the space between them, being completely joined to form the population pyramid.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;&lt;strong&gt;Calculating the population percentages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So far, the data representation obtained, both in the pivot table as in the chart pyramid is based on absolute population numbers. However, the usual practice is that such representation is made ​​as a proportion of each age group and sex on total population.&lt;/p&gt;
&lt;p&gt;For example, in our pivot table, the women population aged between 55 and 59 is 184,888 people; to get the percentage that this population group is in relation to all individuals with whom we are working (6,458,684), we divide the group by the total, and format the result as a percentage, gaining 2.86%.&lt;/p&gt;
&lt;p&gt;If we want the PivotTable to perform this operation for all population groups, we&amp;#39;ll have to add additional calculations in the form of measures, but before that we&amp;#39;ll remove the current population chart, because we will build it again from one of the new measures.&lt;/p&gt;
&lt;p&gt;We start out the existence of a measure, SumaPoblacion, which as we know, it returns the number of people adding the field Sexo_Codigo. The next step is to create a new measure, which included in the pivot table, provide the total population in all cells.&lt;/p&gt;
&lt;p&gt;Our first reaction might be to reuse the RecuentoPoblacion measure, created in the early stages of our example, but soon we realize that it is useless for this purpose, because although this measure counts the Poblacion table rows, the cells result are affected by the fields used in rows and columns, as well as other active filters in the PivotTable.&lt;/p&gt;
&lt;p&gt;For a measure always count all rows in a table, regardless of the filters may be active, we&amp;#39;ll use the CALCULATE function, which as the first parameter pass the operation to perform, in this case the count of rows in the Poblacion table using COUNTROWS function. Then pass as many parameters as filters we want to remove, using the ALL(TableName) function for each table that is, somehow, acting as a filter.&lt;/p&gt;
&lt;p&gt;Under such assumptions create a new measure called TotalGlobalPoblacion, with the following DAX expression:&lt;/p&gt;
&lt;p&gt;=CALCULATE (COUNTROWS (Poblacion), ALL (Edad), ALL (Sexo))&lt;/p&gt;
&lt;p&gt;When applied this measure to the PivotTable, all the cells show the same value: the total population.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;Now we need a third measure that makes the division between the two previous and display the result in percentage format. This new measure will have the name PorcentajePoblacion and use the following formula:&lt;/p&gt;
&lt;p&gt;=[SumaPoblacion] / [TotalGlobalPoblacion]&lt;/p&gt;
&lt;p&gt;As we saw in the first installment of the article, to apply the formatting to this measure will right click on one of its cells choosing &amp;quot;Number Format&amp;quot;. In the format window this time select the &amp;quot;Custom&amp;quot; category, through which we introduce in the &amp;quot;Type&amp;quot; field the following format string.&lt;/p&gt;
&lt;p&gt;0,00%;0,00%&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;This string will format the number as a percentage, and show the male population columns values without the negative sign, but internally, these values ​​will remain negative.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;Next deactivate all PivotTable measures except PorcentajePoblaci&amp;oacute;n, which will be the only one that remains visible. Then again add a clustered bar chart, using the configuration steps outlined above, and adding new format features to improve their presentation.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Apply percentage format to the horizontal axis &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Firstly we will right click on the horizontal axis labels by selecting &amp;quot;Format axis&amp;quot;, which will open the format window. In &amp;quot;Number&amp;quot; section, select the format category &amp;quot;Custom&amp;quot;, and in the &amp;quot;Format Code&amp;quot; field, write the following format string:&lt;/p&gt;
&lt;p&gt;0%;0%&lt;/p&gt;
&lt;p&gt;By clicking the &amp;quot;Add&amp;quot; button, the string is added to the list of custom strings. Accepting the window, the format will apply to the horizontal axis labels.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_5F00_31.JPG" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Emphasizing the population bar edges&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Then we will right click on one of the bars in the chart, choosing again &amp;quot;Format Data Series&amp;quot;. This time, in &amp;quot;Border Color&amp;quot; section, we will click &amp;quot;Solid Line&amp;quot;, selecting black color; while in &amp;quot;Border Styles&amp;quot; assign the value &amp;quot;2 pt.&amp;quot; in property &amp;quot;Width&amp;quot;. This operation will make for both groups of bars in the chart.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;Then we right click on the labels of the age ranges, selecting &amp;quot;Format axis&amp;quot;. In this format window assign the same values ​​for the color and border style properties that just used to the chart bars.&lt;/p&gt;
&lt;p&gt;As a result of these actions, the chart will show the edges with an outline clearly highlighted.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;&lt;strong&gt;Relocating the legend position&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At the time of chart creation, Excel puts the legend (Sexo_DS field) on the right side by default. However, it is possible to change the location of this element if we want to provide more space to the drawing of population bars. To do this, we right-click the legend and select &amp;quot;Format Legend&amp;quot; in the format window, under &amp;quot;Legend Options&amp;quot;, we will click &amp;quot;Top&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;As we can see, the chart has won drawing surface, but the legend indicators have been placed in reverse order with respect to the bars. To solve this problem we will click on the legend (Sexo_DS), dropping a menu of filter options, which will select &amp;quot;Sort Z to A&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_5F00_35.JPG" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;With this action, the legend indicators shall be placed properly, but now we will find that the colors of the bars have been reversed, and lost the edge of the chart bars.&lt;/p&gt;
&lt;p&gt;We will restore the edges of the bars in the manner explained above, whereas in terms of colors, for each side of the pyramid do a right click on one bar and select &amp;quot;Shape Fill&amp;quot;, changing the current color which originally had the chart.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_5F00_36.JPG" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To complete the adjustments we are making about the legend, drag it until it is situated at the same level of the upper element of the pyramid, and will increase its width, so that the indicators are further apart.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;&lt;strong&gt;Clear the ​​fields and add title&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Then we right click on any of the fields of the chart buttons and select the option &amp;quot;Hide All Field Buttons on Chart&amp;quot;. In this way will prevent the user to apply filters on the horizontal and / or vertical pyramid axis, keeping a solid structure thus avoiding the possibility, for example, to hide age ranges either sex. However, this filter feature will still exist from the PivotTable.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;Moreover, in the tab group &amp;quot;PivotChart Tools&amp;quot; we will click on &amp;quot;Layout&amp;quot;, and within the group &amp;quot;Labels&amp;quot; will click on &amp;quot;Chart Title&amp;quot;, which will drop several items where we will choose &amp;quot;Above Chart&amp;quot;, adding a text box to the chart, we will edit to give it a title. At this point we have completed the development of our pyramid.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_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;&lt;strong&gt;Energizing the data pyramid data through slicers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although we have achieved the stated goal of creating a population pyramid, it would be interesting to enrich the information that actually offers as we do in this section.&lt;/p&gt;
&lt;p&gt;Looking at the data model in the PowerPivot window, we shall realize that we haven&amp;#39;t use health zoning information yet, so we can use these data to construct a filter that displays the pyramid based on the population concerning one or more of these health areas.&lt;/p&gt;
&lt;p&gt;PowerPivot pivot tables, in addition to traditional filter, incorporating a new filter type called &amp;quot;slicer&amp;quot;, in addition to the usual filtering functionality provides a more flexible user interface for handle the values ​​to work with.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s create one slicer on the pyramid based on zone information. To this end, on the field list panel, drag the field Zona_DS from Zona table to &amp;quot;Slicers Horizontal&amp;quot; block, resulting in a slice located above both&amp;nbsp;the pivot table and pyramid chart.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_5F00_40.JPG" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To filter data by slicer simply have to select the name of the health area we want to use as a filter. It is also possible to filter several areas simultaneously holding down the Ctrl key while clicking the areas composing the filter (as shown in the figure below).To remove all active filters will click on the icon located in the upper right corner of the slicer.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201204/PopulationPyramidsPowerPivot2_5F00_41.JPG" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;And at this point we concluded the article, in which its two parts we have shown how to construct a population pyramid in Excel 2010, using PowerPivot as a management tool for population data. However, the power of this technology goes beyond the mere treatment of demographic information, covering its scope to any environment where we have to make an analysis with large volumes of data.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=204133" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="DAX" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx" /></entry><entry><title>Population pyramids with PowerPivot. Preparing the data (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/03/26/population-pyramids-with-powerpivot-preparing-the-data-1.aspx" /><id>/blogs/lmblanco/archive/2012/03/26/population-pyramids-with-powerpivot-preparing-the-data-1.aspx</id><published>2012-03-26T16:56:00Z</published><updated>2012-03-26T16:56:00Z</updated><content type="html">&lt;p&gt;A population pyramid is a tool that allows to analyze the status and evolution of a population based on age and sex. This is a feature in demography and statistics, but also cover areas such as health, education, business, etc. For this reason, its integration in an computing information system belonging to one of the areas just mentioned, involves a substantial enrichment in the quality of the results obtained by the users of such systems.&lt;/p&gt;
&lt;p&gt;This article will discuss the construction of population pyramids using PowerPivot, an add-on to Excel 2010 that enables access to large volume data sources and its subsequent management and analysis.&lt;/p&gt;
&lt;p&gt;As we mentioned in the article &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/07/18/generaci-243-n-de-datos-demogr-225-ficos-desde-sql-server.aspx"&gt;Generation of demographic data from SQL Server&lt;/a&gt;, also published in this blog, our current goal (using the PiramidePoblacion database created in that article) is to construct a chart representing a population pyramid similar to what we see in the figure below.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;The first part of the article is devoted to the preparation of PowerPivot data model: connection to a data source, data load and pivot table creation to analyze the population figures. The second part will devote to the construction of the chart that represents the population pyramid, starting from the data on which we worked on the first delivery.&lt;/p&gt;
&lt;p&gt;As in the previously mentioned article, I want to thank again the members of the Health and Studies Reports Service (Directorate of Health Promotion and Prevention, DG Primary Care, Health Ministry CM): Jenaro Astray Mochales, Mar&amp;iacute;a Felicitas Dominguez Berj&amp;oacute;n, Mar&amp;iacute;a Dolores Esteban Vasallo, Beatriz Elvira Rodriguez and especially to Ricard G&amp;egrave;nova Maleras, for the support and guidance received on demographic concepts necessary to be able to properly develop a population pyramid using Excel 2010 in combination with PowerPivot. Besides all this, Ricard has kindly agreed to do a great job of reviewing this article, so the gratitude goes twice.&lt;/p&gt;
&lt;p&gt;I would also like to thank to Enrique Barcel&amp;oacute; for all his great tricks about OLAP development, shared with the team, making a little easier our development work on all these business intelligence tasks.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A little theory&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But before to jump into its creation process, we will provide some brief theoretical notes on population pyramids that allow us to better understand their main features and the information we can collect and analyze from them.&lt;/p&gt;
&lt;p&gt;In essence, a population pyramid is a double histogram that shows the distribution by age and sex of the individuals from a population, either in absolute figures or as percentage of the total population.&lt;/p&gt;
&lt;p&gt;If we are interested in obtaining more detailed information about the conceptual aspects surrounding population pyramids, &lt;a href="http://www.sergas.es/MostrarContidos_N3_T01.aspx?IdPaxina=62714"&gt;Epidat&amp;#39;s 4.0&lt;/a&gt; documentation can be useful. This is an software application developed by the &lt;a href="http://www.sergas.es/MostrarContidos_N3_T01.aspx?IdPaxina=62713"&gt;Ministry of Health of the Xunta de Galicia&lt;/a&gt; and the &lt;a href="http://new.paho.org/blogs/esp/?p=694"&gt;Pan American Health Organization&lt;/a&gt; (OPS, Washington), from whose documentation, we quoted below some of the most important points concerning the issue at hand. First start with some ideas related to the construction of the pyramid.&lt;/p&gt;
&lt;p&gt;&amp;quot;The best way to visualize the distribution by sex and age of a population is, without doubt, the population pyramid, a true icon of demography. A pyramid is a double histogram that allows, at a single glance, to draw up a clear idea not only about the general characteristics of the population (young, aged, with some imbalance by gender) but also specific features which refer to a particular event relative to the population under study.&lt;/p&gt;
&lt;p&gt;Usually the population pyramids are constructed following several conventions and rules:&lt;/p&gt;
&lt;p&gt;- To represent men at left and women at right of the central axis.&lt;/p&gt;
&lt;p&gt;- Locating ages so as to be lower, the closer are the base and vice versa.&lt;/p&gt;
&lt;p&gt;- Maintain a certain proportionality between the base and height (3 widths by 2 levels, or 4 by 3, approximately).&lt;/p&gt;
&lt;p&gt;- Respect the same scale on both sides of the central axis (to facilitate comparison between sexes).&lt;/p&gt;
&lt;p&gt;- Represent the weight of each age interval by the area of ​​each histogram bar, not by its length, which is especially important when working with mixed age groups.&lt;/p&gt;
&lt;p&gt;- Can be built with absolute values, but preferably with the proportions of each age and sex of the total population. &lt;/p&gt;
&lt;p&gt;The last point is important and differentiates the pyramid structure indicators [proportion of young and old, aging index, etc.], which are calculated separately on the total for each respective sex. In the case of the population pyramid, using the total population of both sexes gathered, as the denominator of the proportions, not only ensures the comparability of age distribution, but also by sex.&amp;quot;&lt;/p&gt;
&lt;p&gt;And we will conclude with those items relating to the pyramid&amp;#39;s interpretation.&lt;/p&gt;
&lt;p&gt;&amp;quot;A pyramid by sex and age summarizes the demographic history of a population of at least a hundred years before the reference date (the time it takes roughly one generation to move from the base to the top of the pyramid). Sometimes, the indirect effect of some demographic events is visible beyond the leap of a century (for example, the impact of the sharp decline in fertility in recent decades experienced by many populations will be appreciated, no doubt, in the pyramids of the first half of the XXII). A simple ages pyramid [age by age: 0, 1, 2, 3 ... 99, 100 ...] allows a more accurate analysis than other age groups on aggregate (five-year, ten-year) but also suffers the risk of being affected by quality problems in the records, or be vulnerable to instability of the distributions in small populations.&lt;/p&gt;
&lt;p&gt;The first perception of a pyramid allows to identify the general features of the represented population: a broad-based pyramid that narrows quickly gives an idea of ​​a young population with a high proportion of children and adolescents, adults and elderly low, resulting of high birth and death. Conversely, a pyramid with a narrow profile at the bottom and wide at the top and the middle represents a mature or aged structure. The higher the life expectancy of a population is, most often the inequality by gender is reflected at the top of the pyramid (more full on the side of women, due to their highest level of survival).&lt;/p&gt;
&lt;p&gt;The pyramid does not provide answers for itself, but conducive to the relevant questions arise. The explanations for their profile must be found in historical, social, political and economical events and tendencies that generate consequences in demographic future -that is, in fertility, mortality and migration, which are the phenomena that shape the contours and set the size of a population- and have an interpretation in terms of the triple time perspective: age, period and cohort.&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Incorporating data to PowerPivot&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thanks to VertiPaq, the PowerPivot&amp;#39;s data processing engine, we can achieve unprecedented power and speed in handling, filtering, creating expressions of business logic, and ultimately, in all the analytical operations that we perform on a data model created with this tool.&lt;/p&gt;
&lt;p&gt;The following &lt;a href="http://www.powerpivot.com/"&gt;link&lt;/a&gt; provides access to PowerPivot&amp;#39;s web site, where we can download it, and then install it on our machine, so that we can follow the examples from this article.&lt;/p&gt;
&lt;p&gt;When PowerPivot installation concludes, we will start Excel 2010, creating a new worksheet with the name PiramidePoblacion.xlsx. In the ribbon will have now a new tab with the name &amp;quot;PowerPivot&amp;quot;. Clicking on it will select &amp;nbsp;&amp;quot;PowerPivot Window &amp;quot; belonging to the &amp;quot;Launch&amp;quot; group, which opens the aforementioned PowerPivot window, where define the table structure we will use, or &amp;quot;data model&amp;quot; as referred in PowerPivot development context.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;Then in PowerPivot&amp;#39;s window &amp;quot;Home&amp;quot; tab, we&amp;#39;ll connect to the database using &amp;quot;From Database | From SQL Server&amp;quot; option, from &amp;quot;Get External Data&amp;quot; group.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;This will start the &amp;quot;Table Import Wizard&amp;quot;, where indicate the data source we want to connect.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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 valid data source to develop a population pyramid must have at least information about sex and age of the population, as is the case in PiramidePoblacion database. Additionally, as a way to enrich the analysis to be performed, the database may have additional information as may be the health zoning, population nationality and so on.&lt;/p&gt;
&lt;p&gt;After selecting the PiramidePoblacion database, the next step will provide a list of tables and views that we could import, of which will mark the following: Edad, Poblacion, Sexo y Zona, beginning the import by clicking on &amp;quot;Finish&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;If the import process runs correctly, the wizard will display a summary of the process window.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;After the data entry concludes, we will click &amp;quot;Close&amp;quot; to return to the PowerPivot window, where we find the imported tables arranged in several tabs.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;strong&gt;Analysis using PivotTable&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before go back to the construction phase of the population pyramid, we will use a PivotTable to analyze the figures from the PowerPivot data model, so placed in its working window, we will click on &amp;quot;PivotTable&amp;quot; option, from &amp;quot;Reports&amp;quot; group.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;This will position us in the Excel window, which opens a dialog where we choose the worksheet that will accomodate the PivotTable.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;In our case, selecting the first option and accepting the dialog box, will create the PivotTable on a new worksheet.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;From the &amp;quot;PowerPivot Field List&amp;quot; panel we have at our disposal the fields from the data model tables, which will locate in different areas of the PivotTable (row labels, columns, values, etc.) to carry out our analysis operations. We will use for this a very similar style of work to that we would employ if we were querying an OLAP cube, since the management of the PowerPivot fields here is similar to what we can do with the dimensions and measures contained in a data cube when consulted from Excel.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start with a simple query, consisting in a record count of the Poblacion table, grouping the information by age group, which will place in the PivotTable rows.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll make the record count through a &lt;a href="http://social.technet.microsoft.com/wiki/contents/articles/powerpivot-data-analysis-expressions-dax-language.aspx"&gt;DAX&lt;/a&gt; expression (the PowerPivot query language) located in a calculated measure, which will create by selecting &amp;quot;New Measure&amp;quot;, belonging to the &amp;quot;Measures&amp;quot; group in the &amp;quot;PowerPivot&amp;quot; tab. We&amp;#39;ll apply this measure on the Poblacion table, so we must be previously positioned on it, within the field list panel.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;Selecting this option will open up the &amp;quot;Measure Settings&amp;quot; dialog, and in the formula text box we will write the following expression:&lt;/p&gt;
&lt;p&gt;=COUNTROWS(Poblacion)&lt;/p&gt;
&lt;p&gt;COUNTROWS, as its name suggests, is a function that counts the rows of the table passed as a parameter. To finish creating our measure, give it the name &amp;quot;RecuentoPoblacion&amp;quot; and click &amp;quot;OK&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;Right after creating the measure, it is automatically added to Poblacion table field list and in the &amp;quot;Values&amp;quot; block, showing the table total number of rows 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.201203/PopulationPyramidsPowerPivot_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;Then select in the field list pane, the Edad_Grupo field from Edad table, which automatically placed it in the block &amp;quot;Row Labels&amp;quot;. If this is not the behavior obtained, we&amp;#39;ll manually drag the field and drop in that block.&lt;/p&gt;
&lt;p&gt;As a result of the previous action the pivot table will be updated, showing the Edad_Grupo field values in the rows axis. Regarding figures from RecuentoPoblacion measure, they should be distributed among the sections of each age, to reflect the number of records (population) corresponding for each of these sections. However, as shown in the figure below, this is is not happening, because the measure shows the same value for all rows, which is incorrect.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;strong&gt;Relationships between tables in the model&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Observing the field panel we see that PowerPivot already noticed the problem just discussed, because on top of the panel displays a notice, which informs us that it may be necessary relationship between the tables that are being used to compose the pivot table query.&lt;/p&gt;
&lt;p&gt;This problem would not have occurred if there had been the necessary relationships between tables in the database, but as we said in the article on the creation of the database population, such relations were not created intentionally in order to demonstrate that it is also possible do it so from PowerPivot, as discussed below.&lt;/p&gt;
&lt;p&gt;To let PowerPivot automatically detect the needed connection, we will click the &amp;quot;Create&amp;quot; button next to the notice displayed on the panel fields. As a result, a window will open to create the appropriate relationship, offering additional information on it through the &amp;quot;Details&amp;quot; links.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;After relationship creation, it will be applied immediately on the pivot table without any user intervention, so it will properly display measure values ​​grouped by age.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also possible to manually create relationships between tables in the data model using the PowerPivot working window. To do this we will click the &amp;quot;Create Relationship&amp;quot; option, that belongs to the &amp;quot;Relationships&amp;quot; group, which is located in the &amp;quot;Design&amp;quot; tab of that window.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;This will open a window which will select the table and column representing the source and destination of the relationship.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;This way we will establish two new relationships, which have the Poblacion table as the source and Sexo and Zona tables as a destination. Additionally, using &amp;quot;Manage Relationships&amp;quot; we can see a summary of the relationships created and manage them (create, edit, delete, etc.).&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;These changes just make in the PowerPivot window may affect directly or indirectly the data we are presenting in the pivot table; for that reason, when we return to the Excel window, will see a notice on the field panel, where we click the &amp;quot;Refresh&amp;quot; button to update the data we&amp;#39;re working with.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;&lt;span style="font-weight:bold;"&gt;Adding data to the column axis&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Fixed the relationships problem, now is time to add new data in the pivot table columns through Sexo_DS field from Sexo table.&lt;/p&gt;
&lt;p&gt;When selected, this field is placed by default on the &amp;quot;Row Labels&amp;quot; blocks so we&amp;#39;ll have to manually move it to &amp;quot;Column Labels&amp;quot; block, or directly drag it to the label column block.&lt;/p&gt;
&lt;p&gt;Additionally, we will format the numeric cells either by right-clicking any of them and selecting &amp;quot;Number Format&amp;quot; in the Format dialog box, where we&amp;#39;ll define it without decimal and with thousands separator.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;After these operations, the PivotTable will already display population data according to the requirements posed.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/PopulationPyramidsPowerPivot_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;Now we conclude the first part of this article. In the next installment we will reach our goal of creating a chart that represents the population pyramid using the data we have just prepared with PowerPivot.&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=204029" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="DAX" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx" /></entry><entry><title>Superposed population pyramids with PowerPivot</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/03/15/superposed-population-pyramids-with-powerpivot.aspx" /><id>/blogs/lmblanco/archive/2012/03/15/superposed-population-pyramids-with-powerpivot.aspx</id><published>2012-03-15T22:22:00Z</published><updated>2012-03-15T22:22:00Z</updated><content type="html">&lt;p&gt;In the articles that were dedicated to the creation of a population pyramid using PowerPivot ( &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2012/03/26/population-pyramids-with-powerpivot-preparing-the-data-1.aspx"&gt;part1&lt;/a&gt; and &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/08/21/pir-225-mides-de-poblaci-243-n-con-powerpivot-creaci-243-n-del-gr-225-fico-y-2.aspx"&gt;part2&lt;/a&gt; ), we saw the power that this add-on for Excel provides to users responsible for conducting information analysis on a database of demographic content.&lt;/p&gt;
&lt;p&gt;Continuing the line of work depicted in those articles, this time we will address the development of superposed population pyramids, one aspect of the work with population pyramids, which is to observe and analyze the differences by sex and age structure between two populations by direct comparison of their respective pyramids.&lt;/p&gt;
&lt;p&gt;Before proceeding I want to reiterate my thanks to Ricard G&amp;egrave;nova Maleras, a demographer specializing in population health analysis, belonging to the Reports and Studies Health Service (Directorate of Health Promotion and Prevention, DG Primary Care, Health Ministry CM) for their invaluable review work and guidance on all those concepts about creating population pyramids, which have proved so valuable in the development of this and previous articles we have published about this topic in the blog.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Brief introduction to the superposed population pyramids&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If we want to graphically describe this working scenario, firstly, we take the population pyramids to compare ...&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;... and then place a pyramid on the other, so that we can measure and analyze population differences between them, ending the operation.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If we are managing two static populations, the task is more complex than solely fill the cells in the Excel sheet with the corresponding population figures, and prepare the pyramid-shaped chart that combines the values. However, suppose we have a population base or reference, belonging to all the individuals from a region, and we want to make comparisons between this amount and a classification of the subgroups in which this population can be divided, for example, the geographic or health care areas.&lt;/p&gt;
&lt;p&gt;If the number of zones is very high, this will increase the amount of calculations and subgroups pyramids that we will need developing to compare with the main reference pyramid, increasing the complexity of demographic analysis to be performed.&lt;/p&gt;
&lt;p&gt;At this point of the problem, PowerPivot enters the arena, because if we use to manage population data we must work with, greatly simplify the development of population pyramids and subsequent analysis phase.&lt;/p&gt;
&lt;p&gt;Taking advantage of the pyramid developed in the items listed above, and reflected in the PiramidePoblacion.xlsx file, we will use that work setting as a starting point to develop, in first place, the population pyramids of different health areas, and continue with the reference pyramid creation, that depicts the Community of Madrid population.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The zoning pyramids&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At first glance, this task may seem the most complicated, because its purpose is to create a pyramid for each one of the health area of the population we are dealing with.&lt;/p&gt;
&lt;p&gt;Nothing is further from reality however, because if we followed the early commented articles about pyramids creation, we will have realized that we already have that work done in the PiramidePoblacion.xlsx file, created as an exercise of such of those articles, due to the use of a slicer based on the table Zona, from the PowerPivot data model.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;However, in order to reorganize the names we use in this article, we will remove the measures and pyramid chart we had originally created for the PivotTable. Also change in the window PowertPivot, the table name Poblacion to PoblacionZonas, by right-clicking on the tab for the table, and choosing the menu option &amp;quot;Rename&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Next we will create again the measures for the PoblacionZonas table with the following names and expressions in DAX language.&lt;/p&gt;
&lt;p&gt;/ / PoblacionZonasSuma&lt;/p&gt;
&lt;p&gt;= SUM ([Sexo_Codigo])&lt;/p&gt;
&lt;p&gt;/ / PoblacionZonasTotal&lt;/p&gt;
&lt;p&gt;= CALCULATE (COUNTROWS (PoblacionZonas), ALL (Edad), ALL (Sexo))&lt;/p&gt;
&lt;p&gt;/ / PoblacionZonasPorcentaje&lt;/p&gt;
&lt;p&gt;= [PoblacionZonasSuma] / [PoblacionZonasTotal]&lt;/p&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.201203/SuperposedPopulationPyramidsPowerPivot_5F00_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The way to create and configure the pyramid chart for these populations will be the same as in the articles already mentioned, except the edge of the bars, which in this case be assigned the color white, with a width of 2 points between thereof. Let&amp;#39;s recall that to format the bars will right click on any of them, selecting the menu option &amp;quot;Format Data Series&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In the figure below we can see the chart with the changes just discussed (including the slicer by the field Zona_DS from Zona table), showing the pyramid from one of the available areas.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The reference population pyramid&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The next step is to add to the current chart the pyramid representing the total population, so we will place on the PowerPivot window, where we will repeat the process of adding the Poblacion table from source database to the PowerPivot data model, but this time giving the name PoblacionReferencia to the PowerPivot table, and also creating the calculated column Sexo_Codigo using the following DAX expression: &amp;quot;= IF ([Sexo_ID] =&amp;quot; M &amp;quot;, 1, -1)&amp;quot; cause we need to sum up the population according to sex of individuals.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_08.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_08.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;After this operation we will create the necessary relationships between both population tables and the rest, obtaining the result shown in the figure below.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Then return to the Excel window, where we click the &amp;quot;Refresh&amp;quot; button in the &amp;quot;PowerPivot Field List&amp;quot; window to refresh its content, and incorporate the PoblacionReferencia table that we just added to the PowerPivot window.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_10.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_10.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;With respect to the necessary measures to generate the pyramid corresponding to this reference population, the following code block shows the DAX expressions used for its creation.&lt;/p&gt;
&lt;p&gt;/ / PoblacionReferenciaSuma&lt;a name="mk1"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;CALCULATE = (SUM ([Sexo_Codigo]), ALL (Area))&lt;/p&gt;
&lt;p&gt;/ / PoblacionReferenciaTotal&lt;/p&gt;
&lt;p&gt;= CALCULATE (COUNTROWS (PoblacionReferencia), ALL (Edad), ALL (Sexo), ALL (Area))&lt;/p&gt;
&lt;p&gt;/ / PoblacionReferenciaPorcentaje&lt;/p&gt;
&lt;p&gt;= [PoblacionReferenciaSuma] / [PoblacionReferenciaTotal]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Comparing the measures from the tables PoblacionReferencia and PoblacionZonas, we find in those a significant difference in the operations involved in sum and calculate the total population, consisting in the use of the ALL function applied to the Zona table, which is passed as parameter. Into the measure PoblacionReferenciaSuma we will use, furthermore, the CALCULATE function, so that the addition operation on the reference population table is carried out correctly.&lt;/p&gt;
&lt;p&gt;The ALL function, when operating in a DAX expression used to construct a calculated measure that we use, for example, in a PivotTable, cancels those filters applied to the PivotTable, which are related to table passed as a parameter to the ALL function, and in our case, as mentioned above, affects the Zona table.&lt;/p&gt;
&lt;p&gt;To verify this behavior, that will result in the pyramid of reference at the same time, in the PowerPivot fields window, drag the PoblacionReferenciaPorcentaje field to the Values ​​pane. This will result in new columns insertion into the pivot table for the measure, and bars into the pyramid chart to represent the new population figures.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_11.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_11.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As a next step apply the percentage format to the new columns of figures from the PivotTable, and then do right click on one of the new bars from the population chart, selecting the &amp;quot;Format Data Series&amp;quot;; this action will open the window of the same name, where we modify the following properties / values.&lt;/p&gt;
&lt;p&gt;- Filling: No Fill.&lt;/p&gt;
&lt;p&gt;- Border Color: solid line, color black.&lt;/p&gt;
&lt;p&gt;- Border Styles: width of 1 point.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_12.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201203/SuperposedPopulationPyramidsPowerPivot_5F00_12.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Repeating the same operation on the other bar chart data will complete the visual configuration of the new reference population pyramid, which will stay superposed on the zone pyramid, thus achieving our goal. This result allows us to appreciate the differences between the two types of people, facilitating their analysis.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_13.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_13.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;At this point we conclude this article about construction of population pyramids superposed using PowerPivot as a tool to model our data. In a future article will discuss the development of accumulated pyramids, a variety of population pyramid in which the pyramid bars provide more information, because they allow the inclusion of an additional category of classification.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=203847" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="DAX" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx" /></entry><entry><title>Pirámides de población superpuestas con PowerPivot</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/01/19/pir-225-mides-de-poblaci-243-n-superpuestas-con-powerpivot.aspx" /><id>/blogs/lmblanco/archive/2012/01/19/pir-225-mides-de-poblaci-243-n-superpuestas-con-powerpivot.aspx</id><published>2012-01-19T22:20:00Z</published><updated>2012-01-19T22:20:00Z</updated><content type="html">&lt;p&gt;En los art&amp;iacute;culos que dedic&amp;aacute;bamos a la creaci&amp;oacute;n de una pir&amp;aacute;mide de poblaci&amp;oacute;n empleando PowerPivot (&lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/08/18/pir-225-mides-de-poblaci-243-n-con-powerpivot-preparaci-243-n-del-entorno-de-datos-1.aspx"&gt;parte1&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/08/21/pir-225-mides-de-poblaci-243-n-con-powerpivot-creaci-243-n-del-gr-225-fico-y-2.aspx"&gt;parte2&lt;/a&gt;), pudimos comprobar la potencia que este complemento para Excel proporciona a aquellos usuarios encargados de realizar determinados an&amp;aacute;lisis de informaci&amp;oacute;n sobre una base de datos de contenido demogr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;Continuando la l&amp;iacute;nea de trabajo abierta en aquellos art&amp;iacute;culos, en esta ocasi&amp;oacute;n abordaremos el desarrollo de pir&amp;aacute;mides de poblaci&amp;oacute;n superpuestas, un aspecto del trabajo con pir&amp;aacute;mides demogr&amp;aacute;ficas, que consiste en observar y analizar las diferencias de estructura por sexo y edad existentes entre dos poblaciones, mediante la comparaci&amp;oacute;n directa de sus respectivas pir&amp;aacute;mides.&lt;/p&gt;
&lt;p&gt;Antes de proseguir quisiera reiterar mi agradecimiento a Ricard G&amp;egrave;nova Maleras, dem&amp;oacute;grafo especializado en an&amp;aacute;lisis poblacionales sanitarios, perteneciente al Servicio de Informes de Salud y Estudios (Subdirecci&amp;oacute;n de Promoci&amp;oacute;n de la Salud y Prevenci&amp;oacute;n, DG Atenci&amp;oacute;n Primaria, Consejer&amp;iacute;a Sanidad CM), por su inestimable labor de revisi&amp;oacute;n y orientaci&amp;oacute;n en todos aquellos conceptos sobre creaci&amp;oacute;n de pir&amp;aacute;mides demogr&amp;aacute;ficas, que tan valiosos han resultado en la elaboraci&amp;oacute;n del presente y los anteriores art&amp;iacute;culos que hemos publicado acerca de este mismo tema en el blog.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Breve introducci&amp;oacute;n a las pir&amp;aacute;mides de poblaci&amp;oacute;n superpuestas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si queremos describir gr&amp;aacute;ficamente este escenario de trabajo, en primer lugar tomaremos las pir&amp;aacute;mides de las poblaciones a comparar...&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;...y a continuaci&amp;oacute;n colocaremos una pir&amp;aacute;mide sobre la otra, de forma que podamos apreciar y analizar las diferencias de poblaci&amp;oacute;n existentes entre ambas, finalizando as&amp;iacute; la operaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si se trata de dos poblaciones est&amp;aacute;ticas, la tarea no reviste mayor complejidad que la de rellenar las celdas de la hoja Excel con las cifras de las poblaciones correspondientes, y preparar el gr&amp;aacute;fico con forma de pir&amp;aacute;mide que combine los valores. Sin embargo, supongamos que tenemos una poblaci&amp;oacute;n base o de referencia, perteneciente al total de individuos de una regi&amp;oacute;n, y queremos establecer comparaciones entre ese total y una clasificaci&amp;oacute;n de los subgrupos en que dicha poblaci&amp;oacute;n puede ser dividida, como por ejemplo, las zonas geogr&amp;aacute;ficas o de atenci&amp;oacute;n sanitaria.&lt;/p&gt;
&lt;p&gt;Si el n&amp;uacute;mero de zonas es muy elevado, aumentar&amp;aacute; la cantidad de c&amp;aacute;lculos y pir&amp;aacute;mides de subgrupos que necesitaremos elaborar para comparar con la pir&amp;aacute;mide principal de referencia, increment&amp;aacute;ndose la complejidad del an&amp;aacute;lisis demogr&amp;aacute;fico a realizar.&lt;/p&gt;
&lt;p&gt;Es en este punto del problema donde entra en liza PowerPivot, ya que si lo utilizamos para gestionar los datos de las poblaciones con las que debemos trabajar, simplificaremos en gran medida la elaboraci&amp;oacute;n de las pir&amp;aacute;mides de poblaci&amp;oacute;n, as&amp;iacute; como su posterior fase de an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;Aprovechando la pir&amp;aacute;mide desarrollada en los art&amp;iacute;culos mencionados anteriormente, y&amp;nbsp; plasmada en el archivo PiramidePoblacion.xlsx, utilizaremos dicho escenario de trabajo como punto de partida para elaborar, en primer lugar, las pir&amp;aacute;mides de poblaci&amp;oacute;n de las distintas zonas sanitarias; pasando a continuaci&amp;oacute;n a crear la pir&amp;aacute;mide de referencia, que representa a la poblaci&amp;oacute;n de la Comunidad de Madrid.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Las pir&amp;aacute;mides de zonificaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A simple vista, esta tarea puede parecer la m&amp;aacute;s complicada, debido a que el objetivo de la misma consiste en crear una pir&amp;aacute;mide por cada una de las zonas sanitarias de la poblaci&amp;oacute;n que estamos manejando.&lt;/p&gt;
&lt;p&gt;Nada m&amp;aacute;s lejos de la realidad sin embargo, puesto que si hemos seguido los art&amp;iacute;culos ya comentados sobre creaci&amp;oacute;n de pir&amp;aacute;mides, nos habremos dado cuenta de que ese trabajo ya lo tenemos hecho en el archivo PiramidePoblacion.xlsx, creado como ejercicio de ejemplo de dichos art&amp;iacute;culos, gracias al empleo de una segmentaci&amp;oacute;n basada en la tabla Zona del modelo de datos de PowerPivot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;No obstante, con el fin de reorganizar los nombres que utilizaremos en este art&amp;iacute;culo, vamos a eliminar las medidas y el gr&amp;aacute;fico de la pir&amp;aacute;mide que inicialmente hab&amp;iacute;amos creado para la tabla din&amp;aacute;mica. Tambi&amp;eacute;n cambiaremos, en la ventana de PowertPivot, el nombre de la tabla Poblacion por PoblacionZonas, haciendo clic derecho en la pesta&amp;ntilde;a correspondiente a la tabla, y eligiendo la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Cambiar nombre&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n crearemos de nuevo las medidas de la tabla PoblacionZonas, con los siguientes nombres y expresiones en lenguaje DAX.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;// PoblacionZonasSuma&lt;/p&gt;
&lt;p&gt;=SUM([Sexo_Codigo])&lt;/p&gt;
&lt;p&gt;// PoblacionZonasTotal&lt;/p&gt;
&lt;p&gt;=CALCULATE(COUNTROWS(PoblacionZonas),ALL(Edad),ALL(Sexo))&lt;/p&gt;
&lt;p&gt;// PoblacionZonasPorcentaje&lt;/p&gt;
&lt;p&gt;=[PoblacionZonasSuma] / [PoblacionZonasTotal]&lt;/p&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.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La forma de crear y configurar el gr&amp;aacute;fico de pir&amp;aacute;mide para estas poblaciones ser&amp;aacute; la misma que en los art&amp;iacute;culos ya indicados, con la excepci&amp;oacute;n del borde de las barras, a las que en esta ocasi&amp;oacute;n asignaremos el color blanco, con un ancho de 2 puntos entre las mismas. Recordemos que para dar formato a las barras haremos clic derecho en cualquiera de ellas, seleccionando la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Dar formato a serie de datos&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En la siguiente figura podemos observar el gr&amp;aacute;fico con las modificaciones que acabamos de comentar (incluyendo la segmentaci&amp;oacute;n por el campo Zona_DS de la tabla Zona), mostrando&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; la pir&amp;aacute;mide de una de las zonas disponibles.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La pir&amp;aacute;mide de referencia&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;El siguiente paso consistir&amp;aacute; en a&amp;ntilde;adir al gr&amp;aacute;fico actual la pir&amp;aacute;mide que representar&amp;aacute; al total de la poblaci&amp;oacute;n, para lo cual nos situaremos en la ventana de PowerPivot, donde repetiremos el proceso de agregaci&amp;oacute;n de la tabla Poblacion desde la base de datos origen hasta el modelo de datos de PowerPivot; pero en esta ocasi&amp;oacute;n daremos el nombre PoblacionReferencia a la tabla en PowerPivot, creando tambi&amp;eacute;n la columna calculada Sexo_Codigo con la expresi&amp;oacute;n DAX: &amp;nbsp;&amp;quot;=IF([Sexo_ID] = &amp;quot;M&amp;quot;, 1, -1)&amp;quot;, ya que igualmente necesitaremos sumar la poblaci&amp;oacute;n en funci&amp;oacute;n del sexo de los individuos.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_08.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_08.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tras esta operaci&amp;oacute;n crearemos las oportunas relaciones entre ambas tablas de poblaci&amp;oacute;n y el resto, quedando el resultado mostrado por la siguiente figura.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n volveremos a la ventana de Excel, donde haremos clic en el bot&amp;oacute;n &amp;quot;Actualizar&amp;quot; de la ventana &amp;quot;Lista de campos de PowerPivot&amp;quot;, para que se refresque su contenido, y se incorpore la tabla PoblacionReferencia que acabamos de agregar a la ventana de PowerPivot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_10.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_10.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En cuanto a las medidas necesarias para generar la pir&amp;aacute;mide correspondiente a esta poblaci&amp;oacute;n de referencia, en el siguiente bloque de c&amp;oacute;digo se muestran las expresiones DAX a utilizar para su creaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;// PoblacionReferenciaSuma&lt;/p&gt;
&lt;p&gt;=CALCULATE(SUM([Sexo_Codigo]),ALL(Zona))&lt;/p&gt;
&lt;p&gt;// PoblacionReferenciaTotal&lt;/p&gt;
&lt;p&gt;=CALCULATE(COUNTROWS(PoblacionReferencia),ALL(Edad),ALL(Sexo),ALL(Zona))&lt;/p&gt;
&lt;p&gt;// PoblacionReferenciaPorcentaje&lt;/p&gt;
&lt;p&gt;=[PoblacionReferenciaSuma] / [PoblacionReferenciaTotal]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Comparadas las medidas de la tabla PoblacionZonas y PoblacionReferencia, encontramos en estas &amp;uacute;ltimas una importante diferencia dentro de las operaciones encargadas de sumar la poblaci&amp;oacute;n y calcular su total, consistente en el uso de la funci&amp;oacute;n ALL aplicada a la tabla Zona, la cual es pasada como par&amp;aacute;metro. En la medida PoblacionReferenciaSuma utilizaremos, adem&amp;aacute;s, la funci&amp;oacute;n CALCULATE, para que la operaci&amp;oacute;n de suma sobre la tabla de poblaci&amp;oacute;n de referencia se efect&amp;uacute;e correctamente.&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n ALL, cuando interviene en una expresi&amp;oacute;n DAX utilizada para construir una medida calculada que empleamos, por ejemplo, en una tabla din&amp;aacute;mica, anula aquellos filtros aplicados en la tabla din&amp;aacute;mica, que est&amp;eacute;n relacionados con la tabla pasada como par&amp;aacute;metro a la funci&amp;oacute;n ALL, y que en nuestro caso, como ya hemos mencionado, afecta a la tabla Zona.&lt;/p&gt;
&lt;p&gt;Para comprobar este comportamiento, que al mismo tiempo dar&amp;aacute; como resultado la pir&amp;aacute;mide de referencia, en la ventana de campos de PowerPivot arrastraremos el campo PoblacionReferenciaPorcentaje hasta el panel Valores. Esto producir&amp;aacute; la inserci&amp;oacute;n, en la tabla din&amp;aacute;mica, de nuevas columnas para dicha medida; y en el gr&amp;aacute;fico de pir&amp;aacute;mide, de barras para representar las nuevas cifras de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_11.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_11.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como siguiente paso aplicaremos el formato de porcentaje a las nuevas columnas de cifras de la tabla din&amp;aacute;mica, y a continuaci&amp;oacute;n haremos clic derecho en una de las nuevas barras de poblaci&amp;oacute;n del gr&amp;aacute;fico, seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a serie de datos&amp;quot;; acci&amp;oacute;n esta que abrir&amp;aacute; la ventana del mismo nombre, donde modificaremos las siguientes propiedades/valores.&lt;/p&gt;
&lt;p&gt;--Relleno: Sin Relleno.&lt;/p&gt;
&lt;p&gt;--Color del borde: L&amp;iacute;nea s&amp;oacute;lida, color negro.&lt;/p&gt;
&lt;p&gt;--Estilos de borde: Ancho de 1 punto.&lt;/p&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.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_12.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_12.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Repitiendo esta misma operaci&amp;oacute;n sobre la otra barra de datos del gr&amp;aacute;fico completaremos la configuraci&amp;oacute;n visual de la nueva pir&amp;aacute;mide de poblaci&amp;oacute;n de referencia, que quedar&amp;aacute; superpuesta a la pir&amp;aacute;mide por zonas, logrando as&amp;iacute; nuestro objetivo. Este resultado nos permitir&amp;aacute; apreciar las diferencias entre los dos tipos de poblaci&amp;oacute;n, facilitando su an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_13.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_13.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Llegados a este punto damos&amp;nbsp; por concluido el presente art&amp;iacute;culo sobre construcci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n superpuestas, empleando PowerPivot como herramienta para modelar nuestros datos. En un pr&amp;oacute;ximo art&amp;iacute;culo abordaremos el desarrollo de pir&amp;aacute;mides acumuladas, una variedad de pir&amp;aacute;mide poblacional en la que las barras de la pir&amp;aacute;mide aportan mayor informaci&amp;oacute;n, gracias a que permiten la inclusi&amp;oacute;n de una categor&amp;iacute;a adicional de clasificaci&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=202891" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="DAX" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx" /></entry><entry><title>Optimizando la creación de estructuras de bases de datos en archivos de script mediante SSIS</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/10/15/optimizando-la-creaci-243-n-de-estructuras-de-bases-de-datos-en-archivos-de-script-mediante-ssis.aspx" /><id>/blogs/lmblanco/archive/2011/10/15/optimizando-la-creaci-243-n-de-estructuras-de-bases-de-datos-en-archivos-de-script-mediante-ssis.aspx</id><published>2011-10-15T09:43:00Z</published><updated>2011-10-15T09:43:00Z</updated><content type="html">&lt;p&gt;En el art&amp;iacute;culo &amp;quot;Utilizando SSIS para crear scripts de respaldo con la estructura de la base de datos&amp;quot; (&lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx"&gt;parte 1&lt;/a&gt; - &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/10/03/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-y-2.aspx"&gt;parte 2&lt;/a&gt;), publicado con anterioridad en este blog, dej&amp;aacute;bamos pendiente de desarrollar una mejora que nos permitiera acelerar los tiempos de creaci&amp;oacute;n de los archivos de script, ya que el uso de algunas colecciones proporcionadas por la clase Database, m&amp;aacute;s concretamente Views, StoredProcedures y UserDefinedFunctions, al contener una importante cantidad de objetos del sistema, provocaba que el tiempo de ejecuci&amp;oacute;n del proceso se extendiese m&amp;aacute;s de lo necesario, en el caso de que no necesit&amp;aacute;ramos a&amp;ntilde;adir al script tales tipos de objetos.&lt;/p&gt;
&lt;p&gt;Por tal motivo, la finalidad del presente art&amp;iacute;culo ser&amp;aacute; ofrecer una soluci&amp;oacute;n a dicho problema, exponiendo una t&amp;eacute;cnica mediante la cual conseguiremos reducir los mencionados tiempos de ejecuci&amp;oacute;n. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n del proyecto de Integration Services&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Como gestor de datos utilizaremos &lt;a href="https://www.microsoft.com/betaexperience/pd/SQLDCTP3CTA/enus/"&gt;SQL Server Denali CTP3&lt;/a&gt;, y como entorno de desarrollo &amp;quot;SQL Server Business Intelligence Development Studio&amp;quot; (SSBIDS), con el que crearemos un nuevo proyecto de tipo &amp;quot;Integration Services Project&amp;quot; al que daremos el nombre EstructurasBBDDOptimizado (este proyecto de ejemplo puede descargarse en el siguiente &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201110/EstructurasBBDDOptimizadoZip.txt"&gt;enlace&lt;/a&gt;). Para m&amp;aacute;s detalles acerca de la configuraci&amp;oacute;n del proyecto: paquete de integraci&amp;oacute;n .dtsx, variables, referencias a ensamblados, etc., consultar el proyecto desarrollado en el art&amp;iacute;culo mencionado al comienzo, ya que su modo de creaci&amp;oacute;n es equivalente. En cuanto al c&amp;oacute;digo fuente del paquete, utilizaremos como punto de partida el existente en dicho proyecto, sobre el que progresivamente iremos realizando las modificaciones necesarias.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Las vistas INFORMATION_SCHEMA.XXX&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si queremos averiguar cu&amp;aacute;les son las vistas que el usuario ha creado en una base de datos, tenemos a nuestra disposici&amp;oacute;n la vista del sistema INFORMATION_SCHEMA.VIEWS, que podemos localizar en el nodo &amp;quot;Views | System Views&amp;quot; de SQL Server Management Studio.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una consulta sobre esta vista nos revelar&amp;aacute;, a trav&amp;eacute;s de sus campos TABLE_NAME y TABLE_SCHEMA, el nombre y esquema respectivamente de las vistas de usuario de la base de datos a la que estemos conectados.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De igual manera ocurre para los procedimientos almacenados y funciones, cuyos nombres y esquemas podemos encontrar en los campos ROUTINE_NAME y ROUTINE_SCHEMA de INFORMATION_SCHEMA.ROUTINES, otra vista del sistema, en la que para diferenciar el tipo de objeto emplearemos el campo ROUTINE_TYPE, comprobando que su valor sea &amp;quot;PROCEDURE&amp;quot; o &amp;quot;FUNCTION&amp;quot;.&lt;/p&gt;
&lt;p&gt;Utilizando las anteriores vistas del sistema crearemos, dentro del c&amp;oacute;digo del paquete de nuestro proyecto de integraci&amp;oacute;n, un conjunto de colecciones auxiliares, que contendr&amp;aacute;n, respectivamente, los nombres de las vistas, procedimientos almacenados y funciones de usuario de la base de datos. Posteriormente recorreremos estas colecciones, y por cada uno de sus elementos, accederemos a la colecci&amp;oacute;n-elemento equivalente que existe en la clase Microsoft.SqlServer.Management.Smo.Database, para ejecutar su m&amp;eacute;todo Script, agregando la sentencia de creaci&amp;oacute;n resultante al archivo de script.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Los espacios de nombres System.Data.SqlClient, System.Collections.Specialized y la creaci&amp;oacute;n de colecciones auxiliares&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Accediendo al editor de c&amp;oacute;digo del paquete, comenzaremos a implementar las operaciones que acabamos de describir declarando el espacio de nombres System.Data.SqlClient, mediante el cual tendremos acceso a las clases SqlConnection, SqlCommand y SqlDataReader, necesarias para manipular los objetos de la base de datos con los que deberemos trabajar.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n nos desplazaremos hasta el bucle foreach que recorre la colecci&amp;oacute;n Databases del objeto Server, y mediante una conexi&amp;oacute;n (objeto SqlConnection) contra la base de datos en curso, ejecutaremos una consulta a trav&amp;eacute;s de un objeto SqlCommand sobre la vista INFORMATION_SCHEMA.VIEWS, que nos devolver&amp;aacute;, en forma de objeto SqlDataReader, el conjunto de resultados con los nombres de las vistas y esquemas de la base de datos. Seguidamente recorreremos este SqlDataReader y a&amp;ntilde;adiremos sus valores a un objeto StringCollection (para usar este tipo de colecci&amp;oacute;n declararemos el espacio de nombres System.Collections.Specialized). Como resultado, obtendremos una colecci&amp;oacute;n con los nombres de las vistas de usuario y esquemas de la base de datos que queremos incluir en el script, evitando de esta manera las vistas del sistema.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Data.SqlClient;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Collections.Specialized;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// conexi&amp;oacute;n&lt;/span&gt;&lt;br /&gt;        SqlConnection oConnection = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SqlConnection(&lt;span style="color:#006080;"&gt;&amp;quot;Data Source=&amp;quot;&lt;/span&gt; + oServer.Name +&lt;br /&gt;            &lt;span style="color:#006080;"&gt;&amp;quot;;Initial Catalog=&amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;;Integrated Security=True&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;        SqlCommand oCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SqlCommand();&lt;br /&gt;        oCommand.Connection = oConnection;&lt;br /&gt;        oCommand.CommandType = CommandType.Text;&lt;br /&gt;&lt;br /&gt;        oConnection.Open();&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// vistas&lt;/span&gt;&lt;br /&gt;        oCommand.CommandText = &lt;span style="color:#006080;"&gt;&amp;quot;SELECT TABLE_NAME + &amp;#39; &amp;#39; + TABLE_SCHEMA AS Vista &amp;quot;&lt;/span&gt; +&lt;br /&gt;            &lt;span style="color:#006080;"&gt;&amp;quot;FROM INFORMATION_SCHEMA.VIEWS ORDER BY TABLE_SCHEMA, TABLE_NAME&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;        SqlDataReader oDataReader = oCommand.ExecuteReader();&lt;br /&gt;        StringCollection cllVistas = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; StringCollection();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (oDataReader.Read())&lt;br /&gt;        {&lt;br /&gt;            cllVistas.Add(oDataReader[&lt;span style="color:#006080;"&gt;&amp;quot;Vista&amp;quot;&lt;/span&gt;].ToString());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        oDataReader.Close();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Con respecto a los procedimientos almacenados y funciones procederemos de igual modo, pero empleando en este caso la vista INFORMATION_SCHEMA.ROUTINES para crear las colecciones auxiliares, como vemos en el siguiente bloque de c&amp;oacute;digo.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// procedimientos almacenados&lt;/span&gt;&lt;br /&gt;oCommand.CommandText = &lt;span style="color:#006080;"&gt;&amp;quot;SELECT ROUTINE_NAME + &amp;#39; &amp;#39; + ROUTINE_SCHEMA AS ProcedimientoAlmacenado &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = &amp;#39;PROCEDURE&amp;#39; &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;oDataReader = oCommand.ExecuteReader();&lt;br /&gt;StringCollection cllProcedimientosAlmacenados = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; StringCollection();&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (oDataReader.Read())&lt;br /&gt;{&lt;br /&gt;    cllProcedimientosAlmacenados.Add(oDataReader[&lt;span style="color:#006080;"&gt;&amp;quot;ProcedimientoAlmacenado&amp;quot;&lt;/span&gt;].ToString());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;oDataReader.Close();&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// funciones&lt;/span&gt;&lt;br /&gt;oCommand.CommandText = &lt;span style="color:#006080;"&gt;&amp;quot;SELECT ROUTINE_NAME + &amp;#39; &amp;#39; + ROUTINE_SCHEMA AS Funcion &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = &amp;#39;FUNCTION&amp;#39; &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;oDataReader = oCommand.ExecuteReader();&lt;br /&gt;StringCollection cllFunciones = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; StringCollection();&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (oDataReader.Read())&lt;br /&gt;{&lt;br /&gt;    cllFunciones.Add(oDataReader[&lt;span style="color:#006080;"&gt;&amp;quot;Funcion&amp;quot;&lt;/span&gt;].ToString());&lt;br /&gt;}&lt;br /&gt;oDataReader.Close();&lt;br /&gt;&lt;br /&gt;oConnection.Close();&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de las sentencias para el script&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Finalizada la creaci&amp;oacute;n de las colecciones&amp;nbsp;auxiliares, nuestro siguiente paso consistir&amp;aacute; en crear las sentencias de script para la base de datos y tablas; operaciones que no han sufrido modificaci&amp;oacute;n con respecto al anterior art&amp;iacute;culo, ya que en este caso no debemos lidiar con objetos del sistema.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// base de datos&lt;/span&gt;&lt;br /&gt;oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;oDatabase.Script(oScriptingOptions);&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// tablas&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Table oTable &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Tables)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;        &lt;span style="color:#006080;"&gt;&amp;quot;Procesando tabla: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + oTable.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oTable.Name,&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oTable.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n crearemos un bucle foreach para recorrer cada una de las colecciones auxiliares, accediendo, en cada iteraci&amp;oacute;n, al elemento de la colecci&amp;oacute;n equivalente perteneciente al objeto Database. Para ello, cada cadena (conteniendo los nombres del objeto y esquema, separados por un car&amp;aacute;cter de espacio) que recuperemos de la colecci&amp;oacute;n auxiliar, ser&amp;aacute; asignada, mediante el m&amp;eacute;todo String.Split, a un array de tipo string con dos elementos. Como separador para el m&amp;eacute;todo Split, utilizaremos un array de tipo char con un car&amp;aacute;cter de espacio en blanco.&lt;/p&gt;
&lt;p&gt;Seguidamente, utilizando los valores del array string, accederemos al elemento de la colecci&amp;oacute;n que corresponda en cada caso (Views, StoredProcedures o UserDefinedFunctions) perteneciente al objeto Database, para ejecutar su m&amp;eacute;todo Script. Adicionalmente, emplearemos la enumeraci&amp;oacute;n ObjetosBD en el &amp;iacute;ndice del array, declarada con &amp;aacute;mbito de la clase ScriptMain, para facilitar la lectura del c&amp;oacute;digo.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;enum&lt;/span&gt; ObjetosBD : &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    Nombre,&lt;br /&gt;    Esquema&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main()&lt;br /&gt;{&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&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;char&lt;/span&gt;[] aSeparador = { &lt;span style="color:#006080;"&gt;&amp;#39; &amp;#39;&lt;/span&gt; };&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// vistas&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] aVista;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sVista &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; cllVistas)&lt;br /&gt;            {&lt;br /&gt;                aVista = sVista.Split(aSeparador);&lt;br /&gt;                Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;                    &lt;span style="color:#006080;"&gt;&amp;quot;Procesando vista: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; +&lt;br /&gt;                    aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema] + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre],&lt;br /&gt;                    &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&amp;nbsp;               ((View)oDatabase.Views[&lt;/p&gt;&lt;/pre&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;"&gt;                     aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre], &lt;/pre&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;"&gt;&lt;p&gt;                     aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema]]).Script(oScriptingOptions);&lt;br /&gt;            }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// procedimientos almacenados&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] aProcedimientoAlmacenado;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sProcedimientoAlmacenado &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; cllProcedimientosAlmacenados)&lt;br /&gt;            {&lt;br /&gt;                aProcedimientoAlmacenado = sProcedimientoAlmacenado.Split(aSeparador);&lt;br /&gt;                Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;                    &lt;span style="color:#006080;"&gt;&amp;quot;Procesando procedimiento almacenado: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; +&lt;br /&gt;                    aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema] + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre],&lt;br /&gt;                    &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;                ((StoredProcedure)oDatabase.StoredProcedures[&lt;/p&gt;&lt;/pre&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;"&gt;                     aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre], &lt;/pre&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;"&gt;&lt;p&gt;                     aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema]]).Script(oScriptingOptions);&lt;br /&gt;            }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// funciones&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] aFuncion;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sFuncion &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; cllFunciones)&lt;br /&gt;            {&lt;br /&gt;                aFuncion = sFuncion.Split(aSeparador);&lt;br /&gt;                Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;                    &lt;span style="color:#006080;"&gt;&amp;quot;Procesando funci&amp;oacute;n: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; +&lt;br /&gt;                    aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema] + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre],&lt;br /&gt;                    &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;                ((UserDefinedFunction)oDatabase.UserDefinedFunctions[&lt;/p&gt;&lt;/pre&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;"&gt;                     aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre], &lt;/pre&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;"&gt;                     aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema]]).Script(oScriptingOptions);&lt;br /&gt;            }&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Tras a&amp;ntilde;adir el anterior bloque de c&amp;oacute;digo al paquete de integraci&amp;oacute;n, volveremos a ejecutar &amp;eacute;ste, comprobando c&amp;oacute;mo los tiempos de proceso se reducir&amp;aacute;n notablemente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ajustar el tama&amp;ntilde;o de la base de datos en la sentencia de creaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si abrimos cualquiera de los archivos de script generados tras la ejecuci&amp;oacute;n del paquete, observaremos que la sentencia &amp;quot;CREATE DATABASE&amp;quot; asigna, para los archivos de datos y log, el tama&amp;ntilde;o actual de la base de datos.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Pero supongamos que algunos de estos archivos de datos y log tienen un tama&amp;ntilde;o considerable, y necesitamos que al ser creada la base de datos correspondiente mediante la ejecuci&amp;oacute;n del script, dicho tama&amp;ntilde;o inicial no sea elevado.&lt;/p&gt;
&lt;p&gt;Por tal motivo, la t&amp;eacute;cnica que proponemos para solucionar este problema consiste en acceder y manipular el contenido del archivo de script mediante los m&amp;eacute;todos de las clases File y String, modificando el tama&amp;ntilde;o inicialmente asignado por uno menor. Para ello, pasaremos el contenido del archivo a una variable de tipo string, dentro de la cual, buscaremos las asignaciones de tama&amp;ntilde;o para la base de datos, reemplaz&amp;aacute;ndolas por los nuevos valores. Finalmente, borraremos el archivo original, creando uno nuevo a partir del contenido modificado existente en la variable string.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Ajustando tama&amp;ntilde;o inicial de archivos: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sTextoScript = File.ReadAllText(oScriptingOptions.FileName);&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; nPosicionInicio = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, SIZE&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; nPosicionFin = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, MAXSIZE&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;sTextoScript = sTextoScript.Replace(sTextoScript.Substring(nPosicionInicio, &lt;/p&gt;&lt;/pre&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;"&gt;&lt;p&gt;(nPosicionFin - nPosicionInicio)), &lt;span style="color:#006080;"&gt;&amp;quot;, SIZE = 3072KB&amp;quot;&lt;/span&gt;);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;nPosicionInicio = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, SIZE&amp;quot;&lt;/span&gt;, nPosicionInicio + 6);&lt;br /&gt;nPosicionFin = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, MAXSIZE&amp;quot;&lt;/span&gt;, nPosicionFin + 6);&lt;br /&gt;&lt;br /&gt;sTextoScript = sTextoScript.Replace(sTextoScript.Substring(nPosicionInicio, &lt;/p&gt;&lt;/pre&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;"&gt;&lt;p&gt;(nPosicionFin - nPosicionInicio)), &lt;span style="color:#006080;"&gt;&amp;quot;, SIZE = 1024KB&amp;quot;&lt;/span&gt;);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;File.Delete(oScriptingOptions.FileName);&lt;br /&gt;&lt;br /&gt;File.WriteAllText(oScriptingOptions.FileName, sTextoScript);&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Realizadas las anteriores modificaciones sobre nuestro c&amp;oacute;digo fuente, damos por concluido este art&amp;iacute;culo, en el que hemos expuesto una t&amp;eacute;cnica para optimizar el tiempo empleado por un paquete de Integration Services en generar los archivos de script conteniendo las estructuras de las bases de datos de SQL Server. Espero que os sirva de ayuda.&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=201188" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Integration Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Integration+Services/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="SSIS" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SSIS/default.aspx" /></entry><entry><title>Utilizando SSIS para crear scripts de respaldo con la estructura de la base de datos (y 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/10/03/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-y-2.aspx" /><id>/blogs/lmblanco/archive/2011/10/03/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-y-2.aspx</id><published>2011-10-03T19:02:00Z</published><updated>2011-10-03T19:02:00Z</updated><content type="html">&lt;p&gt;En la &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx"&gt;primera entrega&lt;/a&gt; de este art&amp;iacute;culo realiz&amp;aacute;bamos una introducci&amp;oacute;n al desarrollo de proyectos de Integration Services desde el entorno de BIDS, con el objetivo de crear scripts de la estructura de las bases de datos de nuestro servidor utilizando Script Task, un componente de los paquetes de integraci&amp;oacute;n. Ser&amp;aacute; en esta segunda parte, cuando nos centraremos en la generaci&amp;oacute;n de los mencionados archivos de script.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La clase ScriptingOptions, el m&amp;eacute;todo Script y la generaci&amp;oacute;n del archivo de script&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pasemos a la siguiente fase en el desarrollo de nuestro proceso (el proyecto de Integration Services con los ejemplos puede descargarse &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201110/EstructurasBBDDzip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;), que consistir&amp;aacute; en crear un archivo de script, que de momento solamente incluir&amp;aacute; las sentencias de creaci&amp;oacute;n de la base de datos. Esta operaci&amp;oacute;n ser&amp;aacute; realizada dentro del bucle que recorre la colecci&amp;oacute;n de bases de datos del servidor, obteniendo un archivo por cada base de datos. Previamente deberemos crear la carpeta &amp;quot;C:\EstructurasBBDDCopias&amp;quot;, que ser&amp;aacute; donde se generen los archivos.&lt;/p&gt;
&lt;p&gt;La manera de especificar el archivo de script pasa por utilizar un objeto de la clase ScriptingOptions, que como adivinamos por su nombre, es la encargada de configurar las opciones relativas a la generaci&amp;oacute;n del archivo. Una vez instanciado dicho objeto, la propiedad FileName ser&amp;aacute; la que utilicemos para indicar el nombre y ruta del archivo que se va a crear; mientras que el acto de generaci&amp;oacute;n lo llevaremos a cabo llamando al m&amp;eacute;todo Server.Script, pas&amp;aacute;ndole como par&amp;aacute;metro el objeto ScriptingOptions.&lt;/p&gt;
&lt;p&gt;Dado que este es un proceso que probablemente ejecutaremos con cierta frecuencia, a&amp;ntilde;adiremos las instrucciones necesarias para crear, dentro de la carpeta &amp;quot;C:\EstructurasBBDDCopias&amp;quot;, una subcarpeta cuyo nombre sea la fecha de ejecuci&amp;oacute;n del paquete, siendo esta &amp;uacute;ltima, la carpeta en donde se depositar&amp;aacute;n los archivos de script. Para poder utilizar los objetos necesarios para la manipulaci&amp;oacute;n de carpetas, a&amp;ntilde;adiremos a nuestro c&amp;oacute;digo la declaraci&amp;oacute;n del espacio de nombres System.IO.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.IO;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;Server oServer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Server(&lt;span style="color:#006080;"&gt;&amp;quot;WINTERFELL-PC&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; bOtraVez = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sRutaArchivo = &lt;span style="color:#006080;"&gt;@&amp;quot;C:\EstructurasBBDDCopias\&amp;quot; + DateTime.Today.ToString(&amp;quot;&lt;/span&gt;yyyyMMdd&lt;span style="color:#006080;"&gt;&amp;quot;) + @&amp;quot;\&amp;quot;&lt;/span&gt;;&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (Directory.Exists(sRutaArchivo))&lt;br /&gt;{&lt;br /&gt;    Directory.Delete(sRutaArchivo, &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;
&lt;br /&gt;Directory.CreateDirectory(sRutaArchivo);&lt;br /&gt;
&lt;br /&gt;ScriptingOptions oScriptingOptions = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ScriptingOptions();&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;    oDatabase.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Despu&amp;eacute;s de ejecutar nuevamente el paquete, en la ruta especificada aparecer&amp;aacute;n los archivos reci&amp;eacute;n creados, en cuyo interior encontraremos las sentencias de creaci&amp;oacute;n de la base de datos.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_17.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; [Chinook]&lt;br /&gt; CONTAINMENT = &lt;span style="color:#0000ff;"&gt;NONE&lt;/span&gt;&lt;br /&gt; &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;  &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;br /&gt;( NAME = N&lt;span style="color:#006080;"&gt;&amp;#39;Chinook&amp;#39;&lt;/span&gt;, FILENAME = N&lt;span style="color:#006080;"&gt;&amp;#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Chinook.mdf&amp;#39;&lt;/span&gt; , &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SIZE&lt;/span&gt; = 5184KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )&lt;br /&gt; LOG &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt; &lt;br /&gt;( NAME = N&lt;span style="color:#006080;"&gt;&amp;#39;Chinook_log&amp;#39;&lt;/span&gt;, FILENAME = N&lt;span style="color:#006080;"&gt;&amp;#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Chinook_log.ldf&amp;#39;&lt;/span&gt; , &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SIZE&lt;/span&gt; = 1040KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)&lt;br /&gt; &lt;span style="color:#0000ff;"&gt;COLLATE&lt;/span&gt; Modern_Spanish_CI_AS&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; [Chinook] &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; COMPATIBILITY_LEVEL = 110&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;--....&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Con toda seguridad habremos observado que se han generado archivos tanto para las bases de datos de usuario como de sistema, aunque probablemente en estas &amp;uacute;ltimas no estemos interesados. Si este es el caso, podemos evitar su creaci&amp;oacute;n interrogando a la propiedad Database.IsSystemObject, de tipo bool, mediante la que averiguaremos si se trata de una base de datos de sistema o usuario.&lt;/p&gt;
&lt;p&gt;Con las bases de datos del servidor de informes estamos en una situaci&amp;oacute;n parecida, pero como se trata de bases de datos de usuario, si no queremos generar script para ellas lo haremos comprobando el comienzo de su nombre.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;        oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;        oDatabase.Script(oScriptingOptions);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Modificaci&amp;oacute;n de valores a trav&amp;eacute;s de variables&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para especificar el nombre del servidor con el que trabajamos y la ruta en la que se crear&amp;aacute;n los archivos, actualmente utilizamos valores fijos de cadena, lo cual se convertir&amp;aacute; en un inconveniente cuando tengamos que instalar el paquete en un servidor distinto del utilizado para el desarrollo, o bien queramos emplear una ruta diferente para la creaci&amp;oacute;n de los scripts.&lt;/p&gt;
&lt;p&gt;Podemos remediar este problema gracias a la posibilidad de declarar variables en el dise&amp;ntilde;ador del paquete, cuyos valores pueden ser recuperados desde el c&amp;oacute;digo fuente en el momento de su ejecuci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Para declarar una variable nos situaremos en la ventana &amp;quot;Variables&amp;quot; de Visual Studio y haremos clic en el bot&amp;oacute;n &amp;quot;Add Variable&amp;quot; de su barra de herramientas, cre&amp;aacute;ndose la nueva variable vac&amp;iacute;a, cuyos campos de propiedad (Name, Data type y Value) completaremos con los valores oportunos. En la siguiente imagen vemos la creaci&amp;oacute;n de la variable RutaArchivos, de tipo cadena, con el valor &amp;quot;C:\EstructurasBBDDCopias\&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;En el caso de que esta ventana est&amp;eacute; oculta, la mostraremos seleccionando la opci&amp;oacute;n de men&amp;uacute; de Visual Studio &amp;quot;SSIS | Variables&amp;quot;.&lt;/p&gt;
&lt;p&gt;Adem&amp;aacute;s de las variables creadas por el desarrollador, disponemos tambi&amp;eacute;n de un conjunto de variables de sistema, que podemos visualizar haciendo clic en el bot&amp;oacute;n &amp;quot;Show System Variables&amp;quot; de la barra herramientas de esta misma ventana. Para el ejemplo que estamos desarrollando, haremos uso de la variable &amp;quot;MachineName&amp;quot;, que nos proporcionar&amp;aacute; el nombre del servidor en el que se ejecuta el paquete.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;El siguiente paso consistir&amp;aacute; en preparar las variables para que puedan estar accesibles desde el c&amp;oacute;digo fuente del paquete. Para ello, abriremos la ventana &amp;quot;Script Task Editor&amp;quot; del objeto Script Task, y en la propiedad &amp;quot;ReadOnlyVariables&amp;quot;, perteneciente a la categor&amp;iacute;a &amp;quot;Script&amp;quot;, escribiremos los nombres de las variables como una lista separada por comas, o bien haremos clic en el bot&amp;oacute;n de puntos suspensivos, que abrir&amp;aacute; la ventana &amp;quot;Select Variables&amp;quot;, en donde realizaremos la selecci&amp;oacute;n, lo que tendr&amp;aacute; el mismo efecto.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;A continuaci&amp;oacute;n volveremos a la ventana del editor de c&amp;oacute;digo, donde para recuperar&amp;nbsp;el valor de las variables emplearemos la colecci&amp;oacute;n &amp;quot;Variables&amp;quot; del objeto Dts, situando en el &amp;iacute;ndice de la colecci&amp;oacute;n una cadena con el nombre de la variable a obtener, como vemos en el siguiente bloque de c&amp;oacute;digo.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;Server oServer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Server(Dts.Variables[&lt;span style="color:#006080;"&gt;&amp;quot;System::MachineName&amp;quot;&lt;/span&gt;].Value.ToString());&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; bOtraVez = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sRutaArchivo = Dts.Variables[&lt;span style="color:#006080;"&gt;&amp;quot;User::RutaArchivos&amp;quot;&lt;/span&gt;].Value.ToString() + DateTime.Today.ToString(&lt;span style="color:#006080;"&gt;&amp;quot;yyyyMMdd&amp;quot;&lt;/span&gt;) + @&amp;quot;\&amp;quot;;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Para pasar valores a las variables del paquete, una vez &amp;eacute;ste ha sido importado al servidor de Integration Services, podemos utilizar la ventana &amp;quot;Execute Package Utility&amp;quot;. En la categor&amp;iacute;a &amp;quot;Command Line&amp;quot; haremos clic en el RadioButton &amp;quot;Edit the command line manually&amp;quot;, a&amp;ntilde;adiendo al final de las opciones del comando DTExec la siguiente opci&amp;oacute;n /SET, con la que cambiaremos la ruta en donde se crear&amp;aacute;n los scripts.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;/SET &amp;quot;\Package.Variables[User::RutaArchivos].Value&amp;quot;;&amp;quot;C:\Pruebas\\&amp;quot;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Estos mismos valores ser&amp;aacute;n los que usaremos en el caso de ejecutar el paquete desde la l&amp;iacute;nea de comandos en&amp;nbsp;una ventana &amp;quot;S&amp;iacute;mbolo del sistema&amp;quot; mediante la utilidad DTExec.exe.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;&lt;b&gt;Incorporando las tablas al proceso&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Los siguientes objetos que vamos a generar en el script ser&amp;aacute;n las tablas, por lo que siguiendo la misma mec&amp;aacute;nica utilizada con las bases de datos, crearemos un bucle que recorrer&amp;aacute; la colecci&amp;oacute;n Tables del objeto Database en el que estemos posicionados, a&amp;ntilde;adiendo cada tabla al archivo por medio de su m&amp;eacute;todo Script.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;        oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;        oDatabase.Script(oScriptingOptions);&lt;/p&gt;&lt;p&gt;
&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Table oTable &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Tables)&lt;br /&gt;        {&lt;br /&gt;            Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando tabla: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;                oTable.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oTable.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;            oTable.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Al ejecutar el paquete los archivos ser&amp;aacute;n generados de nuevo, pero si abrimos cualquiera de ellos nos llevaremos una desagradable sorpresa, ya que s&amp;oacute;lo contendr&amp;aacute;n una &amp;uacute;nica sentencia de creaci&amp;oacute;n de tabla. Esto es debido a que, por defecto, el m&amp;eacute;todo Script, cada vez que es llamado, sobrescribe el contenido del archivo con la sentencia reci&amp;eacute;n generada.&lt;/p&gt;
&lt;p&gt;Igualmente nos encontraremos ante otra serie de inconvenientes como son la ausencia de las sentencias para la creaci&amp;oacute;n de los &amp;iacute;ndices de las tablas, claves primarias, externas, etc.&lt;/p&gt;
&lt;p&gt;Para evitar este comportamiento recurriremos nuevamente al objeto ScriptingOptions, asignando el valor true a las propiedades que describimos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;--AppendToFile. Las sentencias generadas mediante el m&amp;eacute;todo Script se ir&amp;aacute;n agregando al archivo sobre el que estamos trabajando, evitando as&amp;iacute; que la &amp;uacute;ltima sentencia reemplace su contenido.&lt;/p&gt;
&lt;p&gt;--IncludeDatabaseContext. Antes de cada sentencia de creaci&amp;oacute;n de tabla se crear&amp;aacute; una sentencia &amp;quot;USE NombreBBDD&amp;quot;, que nos asegure que la tabla sea creada en la base de datos correcta.&lt;/p&gt;
&lt;p&gt;--Indexes. A&amp;ntilde;ade las sentencias para la creaci&amp;oacute;n de &amp;iacute;ndices (agrupados / no agrupados) y claves primarias en las tablas.&lt;/p&gt;
&lt;p&gt;--DriForeignKeys. A&amp;ntilde;ade las sentencias para la creaci&amp;oacute;n de las claves externas de las tablas.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;ScriptingOptions oScriptingOptions = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ScriptingOptions();&lt;br /&gt;oScriptingOptions.AppendToFile = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.IncludeDatabaseContext = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.Indexes = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.DriForeignKeys = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dentro del apartado de creaci&amp;oacute;n de &amp;iacute;ndices, gracias a las propiedades DriPrimaryKey, ClusteredIndexes y NonClusteredIndexes, pertenecientes a la clase ScriptingOptions, vamos a tener la capacidad de ser m&amp;aacute;s selectivos a la hora de elegir el tipo de &amp;iacute;ndice a incluir en el script. Si por ejemplo, en el script solamente queremos a&amp;ntilde;adir sentencias para crear los &amp;iacute;ndices agrupados y las claves primarias, dejando fuera los &amp;iacute;ndices no agrupados, en primer lugar asignaremos false a la propiedad Indexes, para impedir as&amp;iacute; la creaci&amp;oacute;n de todos los tipos de &amp;iacute;ndices, y despu&amp;eacute;s realizaremos la asignaci&amp;oacute;n de las propiedades antes mencionadas, para que sean creados los tipos de &amp;iacute;ndices elegidos.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;oScriptingOptions.Indexes = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.DriPrimaryKey = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.ClusteredIndexes = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.NonClusteredIndexes = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Vistas, procedimientos almacenados, funciones y objetos del sistema&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La inclusi&amp;oacute;n en el proceso de otros objetos de la base de datos tales como vistas, procedimientos almacenados, funciones, etc., no reviste mayor complicaci&amp;oacute;n que la de a&amp;ntilde;adir un nuevo bucle foreach, que recorra la colecci&amp;oacute;n correspondiente del objeto Database: Views, StoredProcedures, UserDefinedFunctions, etc.&lt;/p&gt;
&lt;p&gt;Entre los tipos de objetos que acabamos de mencionar, adem&amp;aacute;s de los creados por el usuario, existen versiones del sistema, y adicionalmente, algunos de estos procedimientos almacenados y funciones del sistema se encuentran encriptados (los reconoceremos&amp;nbsp;en SQL Server Management Studio&amp;nbsp;porque su icono muestra un candado), provocando un error si intentamos incluirlos en el script. Es por ello que debemos evitar esta situaci&amp;oacute;n, consultando su propiedad IsEncypted, como vemos en el siguiente bloque de c&amp;oacute;digo.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_23.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&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;foreach&lt;/span&gt; (View oView &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Views)&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando vista: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oView.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oView.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;        oView.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (StoredProcedure oStoredProcedure &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.StoredProcedures)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!oStoredProcedure.IsEncrypted)&lt;br /&gt;        {&lt;br /&gt;            Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando procedimiento almacenado: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oStoredProcedure.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oStoredProcedure.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;            oStoredProcedure.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (UserDefinedFunction oUserDefinedFunction &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.UserDefinedFunctions)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!oUserDefinedFunction.IsEncrypted)&lt;br /&gt;        {&lt;br /&gt;            Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando funci&amp;oacute;n: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oUserDefinedFunction.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oUserDefinedFunction.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;            oUserDefinedFunction.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Por otra parte, la inclusi&amp;oacute;n de estos objetos del sistema har&amp;aacute; que el archivo de script crezca hasta alcanzar un tama&amp;ntilde;o considerable, por lo que es posible que no deseemos a&amp;ntilde;adirlos.&lt;/p&gt;
&lt;p&gt;Si este es nuestro caso, el modo m&amp;aacute;s sencillo de resolver el problema consiste en asignar false a la propiedad ScriptingOptions.AllowSystemObjects. De esta forma tampoco ser&amp;iacute;a necesario comprobar si ciertos objetos est&amp;aacute;n encriptados, obteniendo adem&amp;aacute;s un archivo de script con un tama&amp;ntilde;o m&amp;aacute;s reducido.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;ScriptingOptions oScriptingOptions = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ScriptingOptions();&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;oScriptingOptions.AllowSystemObjects = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (View oView &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Views)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando vista: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oView.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oView.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oView.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&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;"&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (StoredProcedure oStoredProcedure &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.StoredProcedures)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando procedimiento almacenado: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oStoredProcedure.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oStoredProcedure.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oStoredProcedure.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (UserDefinedFunction oUserDefinedFunction &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.UserDefinedFunctions)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando funci&amp;oacute;n: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oUserDefinedFunction.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oUserDefinedFunction.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oUserDefinedFunction.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Sin embargo, el hecho de no a&amp;ntilde;adir los objetos del sistema al script no va a suponer una mejora significativa en la duraci&amp;oacute;n del proceso, ya que a pesar de que el valor de la propiedad AllowSystemObjects sea false, las colecciones Views, StoredProcedures y UserDefinedFunctions siguen conteniendo los objetos del sistema.&lt;/p&gt;
&lt;p&gt;Con el fin de agilizar estos tiempos de ejecuci&amp;oacute;n, las colecciones que utilizamos para construir el script deber&amp;iacute;an contener &amp;uacute;nica y exclusivamente aquellos objetos que vayamos a incluir en el archivo. No obstante, esta es una tarea de optimizaci&amp;oacute;n que queda fuera del &amp;aacute;mbito del presente art&amp;iacute;culo, pero que abordaremos pr&amp;oacute;ximamente. Por el momento, confiamos en que la soluci&amp;oacute;n aqu&amp;iacute; propuesta&amp;nbsp; resulte de utilidad para todos aquellos lectores que precisen crear scripts con las estructuras de sus bases de datos.&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=200967" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Integration Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Integration+Services/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="SSIS" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SSIS/default.aspx" /></entry><entry><title>Utilizando SSIS para crear scripts de respaldo con la estructura de la base de datos (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx" /><id>/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx</id><published>2011-10-02T14:53:00Z</published><updated>2011-10-02T14:53:00Z</updated><content type="html">&lt;p&gt;Dentro del contexto de cualquier sistema de informaci&amp;oacute;n, resulta fundamental la existencia de una adecuada pol&amp;iacute;tica de copia de seguridad, como medio de contar con un respaldo para proteger los datos almacenados.&lt;/p&gt;
&lt;p&gt;Si nos ce&amp;ntilde;imos, sin embargo, al desarrollo de sistemas Business Intelligence, con cierta frecuencia podemos encontrarnos ante un almac&amp;eacute;n de datos en el que cada vez que debamos procesar los cubos y dimensiones que lo integran, primeramente habremos de vaciar las tablas asociadas a dichos elementos, para recargarlas por completo con datos actualizados provenientes de muy diversas fuentes.&lt;/p&gt;
&lt;p&gt;En un escenario como el que presentamos, antes que la salvaguardia de los datos resulta m&amp;aacute;s importante hacer una copia de la estructura de las tablas, vistas, procedimientos almacenados, etc., de la base de datos, m&amp;aacute;xime si se trata de un almac&amp;eacute;n de datos que se encuentra en pleno proceso de desarrollo, ya que la informaci&amp;oacute;n reside en las fuentes de datos originales que se usan para realizar la carga del almac&amp;eacute;n, las cuales, habitualmente, disponen de sus propios mecanismos de copia de seguridad.&lt;/p&gt;
&lt;p&gt;Por dicho motivo, en el presente art&amp;iacute;culo vamos a centrarnos en desarrollar un proceso que se ocupe de generar, para cada una de las bases de datos de nuestra instancia de SQL Server, un archivo de script con todas las instrucciones de definici&amp;oacute;n (Data Definition Language) de los objetos integrantes de la base de datos. Para lograrlo emplearemos paquetes de SSIS (SQL Server Integration Services), y m&amp;aacute;s concretamente, el componente &amp;quot;Script Task&amp;quot;, que nos otorgar&amp;aacute; un alto grado de flexibilidad y control sobre la generaci&amp;oacute;n de los archivos de script y los objetos de la base de datos a incluir en dichos archivos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Scptxfr.exe. Los or&amp;iacute;genes en SQL Server 2000&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero antes de adentrarnos en el desarrollo del proceso en SSIS, queremos hacer menci&amp;oacute;n a scptxfr.exe, una herramienta que puede resultar de utilidad para aquellos lectores que todav&amp;iacute;a tengan que realizar el mantenimiento de sistemas basados en SQL Server 2000.&lt;/p&gt;
&lt;p&gt;Ejecutada en modo l&amp;iacute;nea de comando&amp;nbsp;desde una ventana &amp;quot;S&amp;iacute;mbolo del sistema&amp;quot;, o bien desde un procedimiento almacenado, tambi&amp;eacute;n nos permite, aunque con menos flexibilidad que en SSIS, como veremos m&amp;aacute;s adelante, generar un conjunto de archivos con las instrucciones de creaci&amp;oacute;n de tablas, &amp;iacute;ndices, claves primarias, vistas, etc., necesarios para la adecuada regeneraci&amp;oacute;n de una base de datos.&lt;/p&gt;
&lt;p&gt;Entre los par&amp;aacute;metros de que dispone, destacaremos los siguientes:&lt;/p&gt;
&lt;p&gt;-- /s. Nombre del servidor SQL Server con el que vamos a trabajar.&lt;/p&gt;
&lt;p&gt;-- /d. Nombre de la base de datos a partir de la que vamos a generar los scripts.&lt;/p&gt;
&lt;p&gt;-- /I. Tipo de autenticaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;-- /F. Nombre (incluyendo ruta si es preciso) del archivo script destino.&lt;/p&gt;
&lt;p&gt;Para una descripci&amp;oacute;n m&amp;aacute;s detallada de todos los par&amp;aacute;metros, sugerimos al lector que ejecute la instrucci&amp;oacute;n SCPTXFR /? desde una ventana de s&amp;iacute;mbolo del sistema.&lt;/p&gt;
&lt;p&gt;De esta forma podr&amp;iacute;amos crear un procedimiento almacenado como el que vemos a continuaci&amp;oacute;n, que recorriera las bases de datos del servidor SQL Server, y creara, por cada una de ellas, una carpeta con los archivos de script correspondientes.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PROCEDURE&lt;/span&gt; CrearEstructurasDB&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; #NombresDBs&lt;br /&gt;(&lt;br /&gt;Linea_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;identity&lt;/span&gt;(1,1), &lt;br /&gt;Nombre &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(150)&lt;br /&gt;)&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;INSERT INTO&lt;/span&gt; #NombresDBs&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; name &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; master..sysdatabases &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; name

&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sDirectorioBak &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @sDirectorioBak = &lt;span style="color:#006080;"&gt;&amp;#39;c:\pruebas\&amp;#39;&lt;/span&gt; + &lt;span style="color:#0000ff;"&gt;convert&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;,getdate(),112) + &lt;span style="color:#006080;"&gt;&amp;#39;\&amp;#39;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nLineaID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nLineaID = 1&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nLineaIDUltimo &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nLineaIDUltimo = (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;MAX&lt;/span&gt;(Linea_ID) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; #NombresDBs)&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sCmdCrearDirectorio &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(200)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sNombreDB &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(150)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sCmd &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(300)&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (@nLineaID &amp;lt;= @nLineaIDUltimo)&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; @sNombreDB = Nombre &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; #NombresDBs &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Linea_ID = @nLineaID&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @sCmdCrearDirectorio = &lt;span style="color:#006080;"&gt;&amp;#39;MKDIR&amp;#39;&lt;/span&gt; + @sDirectorioBak + @sNombreDB&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; master..xp_cmdshell @sCmdCrearDirectorio&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @sCmd = &lt;span style="color:#006080;"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt; + &lt;span style="color:#006080;"&gt;&amp;#39;C:\Archivos de programa\Microsoft SQL Server\MSSQL\Upgrade\scptxfr&amp;#39;&lt;/span&gt; + &lt;span style="color:#006080;"&gt;&amp;#39;&amp;quot; /s &amp;#39;&lt;/span&gt; +&lt;br /&gt;        &lt;span style="color:#cc6633;"&gt;@@servername&lt;/span&gt; + &lt;span style="color:#006080;"&gt;&amp;#39; /d &amp;#39;&lt;/span&gt; + @sNombreDB + &lt;span style="color:#006080;"&gt;&amp;#39; /I /F &amp;#39;&lt;/span&gt; + @sDirectorioBak + @sNombreDB&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; master..xp_cmdshell @sCmd&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nLineaID = @nLineaID + 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;DROP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; #NombresDBs&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dado que el anterior procedimiento almacenado crea los archivos de script en una ruta cuyo nombre incluye la fecha del sistema, podemos programar su ejecuci&amp;oacute;n dentro de una tarea de SQL Server, y obtener de esa forma una copia de respaldo diaria o con la frecuencia que establezcamos, de los scripts de creaci&amp;oacute;n de las bases de datos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;SSIS y los paquetes de integraci&amp;oacute;n. La evoluci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero seg&amp;uacute;n reza su t&amp;iacute;tulo, nos encontramos ante un art&amp;iacute;culo basado en SSIS, por lo que tendremos que usar SQL Server 2005 o superior, ya que es a partir de dicha versi&amp;oacute;n cuando se incluy&amp;oacute; esta tecnolog&amp;iacute;a de integraci&amp;oacute;n de datos.&lt;/p&gt;
&lt;p&gt;Utilizaremos por lo tanto &lt;a href="https://www.microsoft.com/betaexperience/pd/SQLDCTP3CTA/enus/"&gt;SQL Server Denali CTP3&lt;/a&gt;, dado que se trata de la versi&amp;oacute;n m&amp;aacute;s reciente disponible de SQL Server en el momento de desarrollar los ejemplos del art&amp;iacute;culo. Para generar los scripts de estructuras emplearemos las bases de datos &lt;a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"&gt;AdventureWorks2008R2&lt;/a&gt; y &lt;a href="http://chinookdatabase.codeplex.com/releases/view/21111"&gt;Chinook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;El proyecto de servicios de integraci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En primer lugar iniciaremos &amp;quot;SQL Server Business Intelligence Development Studio&amp;quot; (SSBIDS), o lo que es lo mismo, el entorno&amp;nbsp; de desarrollo de Visual Studio 2010, situado en la ruta de men&amp;uacute; &amp;quot;Inicio |Microsoft SQL Server Denali CTP3&amp;quot;.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Esta versi&amp;oacute;n especial de Visual Studio 2010, que acompa&amp;ntilde;a a SQL Server, contiene las plantillas espec&amp;iacute;ficas para la creaci&amp;oacute;n de proyectos de inteligencia de negocio. Por lo que seleccionando la opci&amp;oacute;n de men&amp;uacute; &amp;quot;File | New | Project&amp;quot;, abriremos el di&amp;aacute;logo &amp;quot;New Project&amp;quot;, donde elegiremos un proyecto de tipo &amp;quot;Integration Services Project&amp;quot; al que daremos el nombre EstructurasBBDD.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Este tipo de proyecto incluye por defecto un paquete llamado Package.dtsx, al que cambiaremos el nombre por PckEstructurasBBDD.dtsx, utilizando la propiedad &amp;quot;File Name&amp;quot; de la ventana de propiedades. Tambi&amp;eacute;n podemos hacer clic derecho en el paquete y elegir la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Rename&amp;quot;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_03.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;Script Task. Desarrollo program&amp;aacute;tico de operaciones personalizadas &amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Una vez abierto el paquete, el siguiente paso consistir&amp;aacute; en a&amp;ntilde;adir al dise&amp;ntilde;ador una tarea de c&amp;oacute;digo fuente haciendo doble clic en el icono &amp;quot;Script Task&amp;quot;, situado en la ventana &amp;quot;SSIS Toolbox&amp;quot; del entorno de desarrollo.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n cambiaremos el nombre predeterminado de este elemento por scptEstructurasBBDD editando su propiedad Name.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Escritura y ejecuci&amp;oacute;n del c&amp;oacute;digo de Script Task&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para escribir el c&amp;oacute;digo de nuestras operaciones haremos clic derecho sobre el objeto Script Task, y elegiremos la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Edit&amp;quot;, que abrir&amp;aacute; el di&amp;aacute;logo &amp;quot;Script Task Editor&amp;quot;. De las diversas propiedades disponibles, ScriptLanguage, ubicada dentro de la categor&amp;iacute;a &amp;quot;Script&amp;quot;, nos permite establecer el lenguaje que vamos a usar para programar el proceso (por defecto es C#, aunque tambi&amp;eacute;n podemos utilizar Visual Basic). Haciendo clic en el bot&amp;oacute;n &amp;quot;Edit Script&amp;quot; abriremos el editor de c&amp;oacute;digo de Visual Studio 2010, ventana que nos resultar&amp;aacute; familiar si hemos trabajado anteriormente con este entorno de desarrollo.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;El punto de entrada en la ejecuci&amp;oacute;n del paquete lo representa el m&amp;eacute;todo Main de la clase ScriptMain, que viene integrada por defecto en el c&amp;oacute;digo del paquete. En este m&amp;eacute;todo escribiremos el c&amp;oacute;digo con aquellas operaciones necesarias para interactuar con los objetos de las bases de datos de la instancia de SQL Server con la que vayamos a trabajar.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Para familiarizarnos con el modelo de objetos a manejar y facilitar as&amp;iacute; el aprendizaje del proceso, vamos a comenzar implementando una operaci&amp;oacute;n muy sencilla: recorrer las bases de datos del servidor y visualizar su nombre.&lt;/p&gt;
&lt;p&gt;En primer lugar necesitamos tener acceso a las clases que representan los objetos del servidor SQL, por lo que debemos a&amp;ntilde;adir las siguientes referencias al paquete:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;--Microsoft.SqlServer.ConnectionInfo&lt;/p&gt;
&lt;p&gt;--Microsoft.SqlServer.Management.Sdk.Sfc&lt;/p&gt;
&lt;p&gt;--Microsoft.SqlServer.Smo&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Haciendo clic derecho sobre el nodo &amp;quot;References&amp;quot; de la ventana &amp;quot;Solution Explorer&amp;quot; elegiremos la opci&amp;oacute;n &amp;quot;Add Reference&amp;quot;, que abrir&amp;aacute; un di&amp;aacute;logo con el mismo nombre desde cuya pesta&amp;ntilde;a &amp;quot;.NET&amp;quot; realizaremos la selecci&amp;oacute;n y agregaci&amp;oacute;n de componentes al paquete.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;A continuaci&amp;oacute;n escribiremos el siguiente bloque de c&amp;oacute;digo, que crear&amp;aacute; una instancia de la clase Microsoft.SqlServer.Management.Smo.Server (que representa al servidor SQL), pasando como par&amp;aacute;metros a su constructor una cadena con el nombre del servidor. Utilizando dicho objeto Server, recorreremos su colecci&amp;oacute;n Databases, visualizando el nombre de cada una mediante una ventana MessageBox.&amp;nbsp;&lt;/p&gt;
&lt;div id="Div1"&gt;
&lt;pre id="Pre1" 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;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Data;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Microsoft.SqlServer.Dts.Runtime;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Windows.Forms;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Microsoft.SqlServer.Management.Smo;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main()&lt;br /&gt;{&lt;br /&gt;    Server oServer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Server(&lt;span style="color:#006080;"&gt;&amp;quot;WINTERFELL-PC&amp;quot;&lt;/span&gt;);&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;    {&lt;br /&gt;        MessageBox.Show(oDatabase.Name);&lt;br /&gt;    }&lt;br /&gt;
&lt;br /&gt;    Dts.TaskResult = (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ScriptResults.Success;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Seguidamente cerraremos el editor de c&amp;oacute;digo y aceptaremos el di&amp;aacute;logo &amp;quot;Script Task Editor&amp;quot;, poniendo en ejecuci&amp;oacute;n el paquete mediante la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Debug | Start debugging&amp;quot; o pulsando la tecla F5, que ir&amp;aacute; mostrando los mensajes correspondientes con los nombres de las bases de datos.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Finalizada la ejecuci&amp;oacute;n, haremos clic en el enlace &amp;quot;Package execution completed...&amp;quot; que aparece en la parte inferior del dise&amp;ntilde;ador del paquete, o seleccionaremos la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Debug | Stop Debugging&amp;quot; para salir de la ejecuci&amp;oacute;n desde el depurador.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;No obstante, a pesar de resultar factible, no consideramos muy adecuado el uso de MessageBox para comunicar informaci&amp;oacute;n al usuario acerca de la ejecuci&amp;oacute;n del paquete, ya que estimamos que en un alto porcentaje de las ocasiones, un paquete de estas caracter&amp;iacute;sticas se desarrolla para su ejecuci&amp;oacute;n desatendida a trav&amp;eacute;s de una tarea (Job) del Agente de SQL Server.&lt;/p&gt;
&lt;p&gt;Si bien con el depurador podemos obtener toda la informaci&amp;oacute;n necesaria en tiempo de ejecuci&amp;oacute;n, su uso se limita a Visual Studio, por lo que solamente puede ser utilizado durante la fase de desarrollo del paquete. Debemos, por lo tanto, encontrar un medio alternativo para poder informar al usuario de lo que est&amp;aacute; sucediendo durante la ejecuci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n a este problema la encontramos en el m&amp;eacute;todo &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.dts.runtime.idtscomponentevents.fireinformation(v=SQL.110).aspx"&gt;Dts.Events.FireInformation&lt;/a&gt;, que hace que el paquete env&amp;iacute;e un evento informativo al exterior. Sustituyendo la llamada a MessageBox.Show por este otro m&amp;eacute;todo, nuestro c&amp;oacute;digo quedar&amp;aacute; como vemos a continuaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; bOtraVez = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma, al ejecutar el paquete podremos realizar un seguimiento en la ejecuci&amp;oacute;n del mismo desde la pesta&amp;ntilde;a &amp;quot;Execution Results&amp;quot; (&amp;quot;Progress&amp;quot; en tiempo de ejecuci&amp;oacute;n) del dise&amp;ntilde;ador, y tambi&amp;eacute;n desde la ventana &amp;quot;Output&amp;quot; del depurador, donde veremos los mensajes generados mediante el m&amp;eacute;todo FireInformation.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;&lt;b&gt;Ejecutando el paquete fuera del entorno de &lt;/b&gt;&lt;b&gt;SSBIDS&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero comprobemos, ejecutando el paquete de forma independiente, que estos mensajes de notificaci&amp;oacute;n tambi&amp;eacute;n funcionan fuera del entorno de SSBIDS. Supongamos que el archivo PckEstructurasBBDD.dtsx del proyecto de integraci&amp;oacute;n que estamos desarrollando se encuentra en la ruta C:\pruebasSSIS\EstructurasBBDD\EstructurasBBDD; lo primero que tenemos que hacer es iniciar SQL Server Management Studio (SSMS), conectando con el servicio &amp;quot;Integration Services&amp;quot; como vemos en la siguiente imagen.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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 continuaci&amp;oacute;n desplegaremos&amp;nbsp; los nodos &amp;quot;Stored Packages | File System&amp;quot;, haremos clic derecho en este &amp;uacute;ltimo, y seleccionaremos la opci&amp;oacute;n &amp;quot;Import Package&amp;quot;, abri&amp;eacute;ndose una ventana con el mismo nombre. En esta ventana desplegaremos la lista &amp;quot;Package location&amp;quot;, eligiendo &amp;quot;File System&amp;quot;, mientras que en el campo &amp;quot;Package path&amp;quot; introduciremos la ruta y el nombre del archivo .dtsx perteneciente al paquete que estamos programando. El nombre del paquete (campo Package name) se rellena por defecto con el mismo del archivo .dtsx, aunque podemos utilizar otro distinto.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Una vez completados los campos de esta ventana haremos clic en &amp;quot;OK&amp;quot;, siendo el paquete agregado al servidor de Integration Services de SQL Server.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Ejecutaremos el paquete haciendo clic derecho en el mismo y seleccionando la opci&amp;oacute;n &amp;quot;Run Package&amp;quot;, que abrir&amp;aacute; la ventana &amp;quot;Execute Package Utility&amp;quot;, en la que haremos clic en el bot&amp;oacute;n &amp;quot;Execute&amp;quot;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Esta ventana utiliza internamente el ejecutable DTExec.exe, que tambi&amp;eacute;n podemos usar desde una ventana &amp;quot;S&amp;iacute;mbolo del sistema&amp;quot;, como explicaremos en la segunda parte del art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;Durante la ejecuci&amp;oacute;n del paquete, la ventana &amp;quot;Package Execution Progress&amp;quot; mostrar&amp;aacute; una serie de mensajes informativos acerca de su progreso, incluyendo aquellos que enviamos desde el c&amp;oacute;digo fuente utilizando el m&amp;eacute;todo FireInformation anteriormente explicado.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_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;Llegados a este punto hacemos una peque&amp;ntilde;a parada en el camino y concluimos esta primera parte del art&amp;iacute;culo. En la segunda entrega abordaremos la creaci&amp;oacute;n de los archivos de script que contendr&amp;aacute;n las sentencias para crear los objetos de nuestras bases de datos. Mientras tanto, el lector que quiera experimentar con el proyecto de integraci&amp;oacute;n desarrollado a lo largo del art&amp;iacute;culo, puede descargarlo &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201110/EstructurasBBDDzip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Saludos.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=200913" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Integration Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Integration+Services/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="SSIS" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SSIS/default.aspx" /></entry><entry><title>Pirámides de población con PowerPivot. Creación del gráfico (y 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/08/21/pir-225-mides-de-poblaci-243-n-con-powerpivot-creaci-243-n-del-gr-225-fico-y-2.aspx" /><id>/blogs/lmblanco/archive/2011/08/21/pir-225-mides-de-poblaci-243-n-con-powerpivot-creaci-243-n-del-gr-225-fico-y-2.aspx</id><published>2011-08-21T17:58:00Z</published><updated>2011-08-21T17:58:00Z</updated><content type="html">&lt;p&gt;En la primera parte de este art&amp;iacute;culo desarroll&amp;aacute;bamos un modelo de datos en PowerPivot que representaba las cifras de una poblaci&amp;oacute;n por edad y sexo. En esta segunda entrega plasmaremos dichas cifras en un gr&amp;aacute;fico con forma de pir&amp;aacute;mide de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Gr&amp;aacute;fico de pir&amp;aacute;mide. Primer acercamiento&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En su estado actual, la tabla din&amp;aacute;mica ya tendr&amp;iacute;a la informaci&amp;oacute;n suficiente (cifras de poblaci&amp;oacute;n, edad y sexo) como para intentar crear un gr&amp;aacute;fico que represente una pir&amp;aacute;mide de poblaci&amp;oacute;n; aunque adelantamos al lector que en esta primera aproximaci&amp;oacute;n no vamos a conseguir el efecto deseado.&lt;/p&gt;
&lt;p&gt;Posicionados en la tabla din&amp;aacute;mica, dentro de la cinta de opciones de Excel seleccionaremos la opci&amp;oacute;n &amp;quot;Gr&amp;aacute;fico din&amp;aacute;mico&amp;quot;, perteneciente al grupo &amp;quot;Herramientas&amp;quot; de la ficha &amp;quot;Opciones&amp;quot;, que a su vez est&amp;aacute; contenida en la ficha de nivel superior &amp;quot;Herramientas de tabla din&amp;aacute;mica&amp;quot;.&lt;/p&gt;
&lt;p&gt;Esta selecci&amp;oacute;n abrir&amp;aacute; la ventana &amp;quot;Insertar gr&amp;aacute;fico&amp;quot;, que contiene el conjunto de tipos de gr&amp;aacute;fico disponibles. Aqu&amp;iacute; nos percataremos de que no existe una plantilla espec&amp;iacute;fica para crear un gr&amp;aacute;fico de pir&amp;aacute;mide; por lo tanto, entre toda la oferta a nuestra disposici&amp;oacute;n elegiremos, dentro de la categor&amp;iacute;a &amp;quot;Barra&amp;quot;, el tipo &amp;quot;Barra agrupada&amp;quot;, que como veremos m&amp;aacute;s adelante ser&amp;aacute; el que mejor se adaptar&amp;aacute; al resultado que queremos conseguir.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;Aceptando esta ventana, el gr&amp;aacute;fico ser&amp;aacute; creado a partir de los datos de la tabla din&amp;aacute;mica, y tal y como hab&amp;iacute;amos anticipado, el resultado no se parecer&amp;aacute; a la imagen presentada al principio del art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;No obstante, la principal diferencia radica en el dibujo de la barra correspondiente a la poblaci&amp;oacute;n de hombres, cuyo sentido deber&amp;iacute;a ser hacia la izquierda; el resto de aspectos son b&amp;aacute;sicamente cuestiones de configuraci&amp;oacute;n visual, que posteriormente explicaremos c&amp;oacute;mo resolver.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Solucionando la trayectoria de las barras de poblaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Centr&amp;aacute;ndonos en la barra de poblaci&amp;oacute;n masculina, la soluci&amp;oacute;n para conseguir que se dibuje en direcci&amp;oacute;n opuesta a la que actualmente tiene, consiste en poner en negativo los valores de las celdas de la tabla din&amp;aacute;mica correspondientes a este segmento de la poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Si nos encontr&amp;aacute;ramos en una hoja de c&amp;aacute;lculo simple, sin conexi&amp;oacute;n a PowerPivot, la soluci&amp;oacute;n ser&amp;iacute;a tan sencilla como editar las celdas de la columna Hombre, pasando sus valores a negativo, pero estamos en un escenario de trabajo en el que los datos est&amp;aacute;n siendo obtenidos desde el modelo de datos de PowerPivot, por lo que no es posible editar directamente los valores de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;Para solucionar esta clase de problemas tendremos que recurrir a la creaci&amp;oacute;n de columnas y/o medidas calculadas, que a trav&amp;eacute;s de expresiones DAX proporcionen los resultados que necesitamos. En el caso del paso a negativo de los valores de la columna Hombre, abriremos la ventana de PowerPivot, y situ&amp;aacute;ndonos en la primera columna vac&amp;iacute;a disponible en la tabla Poblaci&amp;oacute;n, escribiremos la siguiente expresi&amp;oacute;n en la barra de f&amp;oacute;rmulas:&lt;/p&gt;
&lt;p&gt;=IF([Sexo_ID] = &amp;quot;M&amp;quot;, 1, -1)&lt;/p&gt;
&lt;p&gt;Acabamos de crear una columna calculada que se evaluar&amp;aacute; para cada fila de la tabla Poblaci&amp;oacute;n, comprobando si el valor del campo Sexo_ID es igual a la letra &amp;quot;M&amp;quot;, en caso afirmativo, el valor de la columna en dicha fila ser&amp;aacute; 1, en caso contrario (cuando el campo contenga &amp;quot;H&amp;quot;) el valor devuelto ser&amp;aacute; -1.&lt;/p&gt;
&lt;p&gt;Seguidamente haremos doble clic sobre su cabecera para asignarle el nombre Sexo_Codigo. Tambi&amp;eacute;n podemos darle nombre haciendo clic derecho sobre la cabecera y eligiendo la opci&amp;oacute;n &amp;quot;Cambiar nombre de columna&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_24b.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Volviendo nuevamente a la ventana de Excel, eliminaremos el gr&amp;aacute;fico que hab&amp;iacute;amos creado en la hoja y desmarcaremos la medida RecuentoPoblacion, quedando vac&amp;iacute;a la zona de valores de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;El pr&amp;oacute;ximo paso a dar consistir&amp;aacute; en crear una nueva medida con el nombre SumaPoblacion, basada en la siguiente expresi&amp;oacute;n DAX:&lt;/p&gt;
&lt;p&gt;=SUM( [Sexo_Codigo] )&lt;/p&gt;
&lt;p&gt;Al aplicar esta medida a la tabla din&amp;aacute;mica, la funci&amp;oacute;n SUM realiza la suma de los valores de la columna pasada como par&amp;aacute;metro, por lo que las cifras de la poblaci&amp;oacute;n de hombres ya aparecer&amp;aacute;n en negativo. Esto significa que al volver a crear el gr&amp;aacute;fico en el modo antes explicado, las barras indicadoras de los valores de poblaci&amp;oacute;n por sexo se dibujar&amp;aacute;n ahora en direcciones opuestas. Como detalle adicional, en la ficha &amp;quot;Herramientas de tabla din&amp;aacute;mica&amp;quot;, dentro de la ficha &amp;quot;Dise&amp;ntilde;o&amp;quot;, en el grupo &amp;quot;Dise&amp;ntilde;o&amp;quot; desplegaremos la opci&amp;oacute;n &amp;quot;Totales generales&amp;quot;, seleccionando el valor &amp;quot;Activado s&amp;oacute;lo para columnas&amp;quot;, que ocultar&amp;aacute; la columna de totales de fila, ya que su presencia en este contexto resulta irrelevante.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;&lt;b&gt;Configuraci&amp;oacute;n visual de las barras de poblaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Aunque las barras del gr&amp;aacute;fico ya se muestran seg&amp;uacute;n el efecto que nos hab&amp;iacute;amos propuesto como objetivo, ser&amp;iacute;a deseable que su aspecto visual recibiera algunos retoques para mejorar la calidad de su presentaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;En primer lugar haremos clic derecho sobre las etiquetas de los rangos de edad, seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a eje&amp;quot;. En la ventana del mismo nombre, dentro del apartado &amp;quot;Opciones del eje&amp;quot;, asignaremos el valor &amp;quot;Bajo&amp;quot; a la propiedad &amp;quot;Etiquetas del eje&amp;quot;, lo que tendr&amp;aacute; como resultado que esta columna de etiquetas quede alineada a la izquierda del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;A continuaci&amp;oacute;n haremos clic derecho sobre cualquiera de las barras del gr&amp;aacute;fico, eligiendo la opci&amp;oacute;n &amp;quot;Dar formato a serie de datos&amp;quot;. En la ventana de configuraci&amp;oacute;n de la serie, dentro del apartado &amp;quot;Opciones de la serie&amp;quot;, en la propiedad &amp;quot;Superposici&amp;oacute;n de series&amp;quot;, desplazaremos el marcador de posici&amp;oacute;n hasta el extremo derecho (totalmente superpuesta), mientras que en la propiedad &amp;quot;Ancho del intervalo&amp;quot; desplazaremos el marcador de posici&amp;oacute;n hasta el extremo izquierdo (sin intervalo en absoluto). De esta forma conseguiremos que las barras aumenten su grosor y eliminen el espacio intermedio entre las mismas, quedando completamente unidas para formar la pir&amp;aacute;mide de poblaci&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.201108/PiramidesPoblacionPowerPivot_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;&lt;b&gt;Calculando la poblaci&amp;oacute;n en porcentajes&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La representaci&amp;oacute;n de los datos obtenida hasta este momento, tanto en la tabla din&amp;aacute;mica como en el gr&amp;aacute;fico de pir&amp;aacute;mide, se basa en cifras absolutas de poblaci&amp;oacute;n. Sin embargo, lo habitual y recomendable es que dicha representaci&amp;oacute;n se realice como proporci&amp;oacute;n de cada grupo de edad y sexo sobre el total de la poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Por ejemplo, en nuestra tabla din&amp;aacute;mica, la poblaci&amp;oacute;n de mujeres con edades comprendidas entre los 55 y 59 a&amp;ntilde;os es de 184.888 personas; para obtener el porcentaje que este grupo de poblaci&amp;oacute;n constituye en relaci&amp;oacute;n al total de individuos con el que estamos trabajando (6.458.684), dividiremos el grupo entre el total, y formatearemos el resultado como porcentaje, obteniendo 2,86 %.&lt;/p&gt;
&lt;p&gt;Si queremos que la tabla din&amp;aacute;mica realice esta operaci&amp;oacute;n para todos los grupos de poblaci&amp;oacute;n tendremos que a&amp;ntilde;adir c&amp;aacute;lculos adicionales en forma de medidas, pero antes de eso eliminaremos el actual gr&amp;aacute;fico de poblaci&amp;oacute;n, ya que volveremos a construirlo a partir de una de las nuevas medidas.&lt;/p&gt;
&lt;p&gt;Partimos de la existencia de una medida, SumaPoblacion, que como ya sabemos, devuelve la cifra de poblaci&amp;oacute;n sumando el campo Sexo_Codigo. El siguiente paso consistir&amp;aacute; en crear una nueva medida, que al incluirse en la tabla din&amp;aacute;mica, proporcione el total de poblaci&amp;oacute;n en todas las celdas.&lt;/p&gt;
&lt;p&gt;Nuestra primera reacci&amp;oacute;n podr&amp;iacute;a ser volver a utilizar la medida RecuentoPoblacion, creada en las fases iniciales de nuestro ejemplo, pero pronto nos daremos cuenta de que no sirve para este prop&amp;oacute;sito, ya que aunque esta medida cuenta las filas de la tabla Poblaci&amp;oacute;n, los resultados de las celdas se ven afectados por los campos utilizados en filas y columnas, as&amp;iacute; como otros filtros que pudiera tener activos la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;Para que una medida cuente siempre todas las filas de una tabla, sin importar los filtros que pueda haber activos, utilizaremos la funci&amp;oacute;n CALCULATE, a la que pasaremos como primer par&amp;aacute;metro la operaci&amp;oacute;n a realizar, en este caso el recuento de filas de la tabla Poblaci&amp;oacute;n mediante la funci&amp;oacute;n COUNTROWS. A continuaci&amp;oacute;n pasaremos tantos par&amp;aacute;metros como filtros queramos eliminar, utilizando la funci&amp;oacute;n ALL(NombreTabla) por cada tabla que de alguna manera est&amp;eacute; actuando como filtro.&lt;/p&gt;
&lt;p&gt;Bajo tales premisas crearemos una nueva medida llamada TotalGlobalPoblacion, con la siguiente expresi&amp;oacute;n DAX:&lt;/p&gt;
&lt;p&gt;=CALCULATE(&amp;nbsp; COUNTROWS( Poblacion ), ALL( Edad), ALL( Sexo ) )&lt;/p&gt;
&lt;p&gt;Al aplicar sobre la tabla din&amp;aacute;mica esta medida, todas sus celdas mostrar&amp;aacute;n el mismo valor: el&amp;nbsp; total de la poblaci&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.201108/PiramidesPoblacionPowerPivot_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;Ahora necesitamos una tercera medida que haga la divisi&amp;oacute;n entre las dos anteriores y muestre el resultado en formato porcentaje. Esta nueva medida tendr&amp;aacute; el &amp;quot;original&amp;quot; nombre de PorcentajePoblacion y utilizara la siguiente f&amp;oacute;rmula:&lt;/p&gt;
&lt;p&gt;=[SumaPoblacion] / [TotalGlobalPoblacion]&lt;/p&gt;
&lt;p&gt;Como ya vimos en la primera entrega del art&amp;iacute;culo, para aplicar el formato a esta medida haremos clic derecho en una de sus celdas eligiendo la opci&amp;oacute;n &amp;quot;Formato de n&amp;uacute;mero&amp;quot;. En la ventana de formato seleccionaremos esta vez la categor&amp;iacute;a &amp;quot;Personalizada&amp;quot;, a trav&amp;eacute;s de la cual introduciremos en el campo &amp;quot;Tipo&amp;quot; la siguiente cadena de formato propia.&lt;/p&gt;
&lt;p&gt;0,00%;0,00%&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;Esta cadena, adem&amp;aacute;s de formatear el n&amp;uacute;mero como porcentaje, mostrar&amp;aacute; sin el signo negativo los valores de la columna de poblaci&amp;oacute;n masculina, aunque internamente, dichos valores seguir&amp;aacute;n siendo negativos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;A continuaci&amp;oacute;n desactivaremos todas las medidas de la tabla din&amp;aacute;mica a excepci&amp;oacute;n de PorcentajePoblaci&amp;oacute;n, que ser&amp;aacute; la &amp;uacute;nica que permanecer&amp;aacute; visible. Seguidamente volveremos a a&amp;ntilde;adir un gr&amp;aacute;fico de barras agrupadas, en el que adem&amp;aacute;s de utilizar los pasos de configuraci&amp;oacute;n explicados con anterioridad, agregaremos nuevas caracter&amp;iacute;sticas de formato para mejorar su presentaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Aplicar formato de porcentaje al eje horizontal &lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En primer lugar haremos clic derecho en el eje horizontal de etiquetas seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a eje&amp;quot;, que abrir&amp;aacute; la ventana de formato, en cuyo apartado &amp;quot;N&amp;uacute;mero&amp;quot; seleccionaremos la categor&amp;iacute;a de formato &amp;quot;Personalizado&amp;quot; y en el campo &amp;quot;C&amp;oacute;digo de formato&amp;quot; escribiremos la siguiente cadena de formato:&lt;/p&gt;
&lt;p&gt;0%;0%&lt;/p&gt;
&lt;p&gt;Haciendo clic en el bot&amp;oacute;n &amp;quot;Agregar&amp;quot;, la cadena se a&amp;ntilde;adir&amp;aacute; a la lista de cadenas personalizadas, de modo que al aceptar la ventana se aplicar&amp;aacute; el formato al eje horizontal de etiquetas.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_31.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;Remarcando los bordes de las barras de poblaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Seguidamente haremos clic sobre alguna de las barras del gr&amp;aacute;fico, volviendo a elegir la opci&amp;oacute;n &amp;quot;Dar formato a serie de datos&amp;quot;. En esta ocasi&amp;oacute;n, dentro del apartado &amp;quot;Color del borde&amp;quot; haremos clic en la opci&amp;oacute;n &amp;quot;L&amp;iacute;nea s&amp;oacute;lida&amp;quot;, seleccionando el color negro; mientras que en el apartado &amp;quot;Estilos del borde&amp;quot; asignaremos a la propiedad &amp;quot;Ancho&amp;quot; el valor &amp;quot;2 pto&amp;quot;. Esta operaci&amp;oacute;n la realizaremos para ambos grupos de barras del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;Despu&amp;eacute;s haremos clic derecho sobre las etiquetas de los rangos de edad, seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a eje&amp;quot;. En esta ventana de formato asignaremos los mismos valores para las propiedades de color y estilo de borde que acabamos de utilizar para las barras del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;Como resultado de estas acciones, el gr&amp;aacute;fico mostrar&amp;aacute; sus bordes con un contorno claramente remarcado.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Reubicando la posici&amp;oacute;n de la leyenda&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En el momento de crear el gr&amp;aacute;fico, Excel sit&amp;uacute;a por defecto la leyenda (campo Sexo_DS) en el lado derecho. No obstante, es posible cambiar la ubicaci&amp;oacute;n de este elemento si queremos proporcionar m&amp;aacute;s espacio al dibujo de las barras de poblaci&amp;oacute;n. Para ello, haremos clic derecho en la leyenda y seleccionaremos la opci&amp;oacute;n &amp;quot;Formato de leyenda&amp;quot;, en la ventana de formato, dentro del apartado &amp;quot;Opciones de leyenda&amp;quot;, haremos clic en la opci&amp;oacute;n &amp;quot;Superior&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;Como podemos apreciar, el gr&amp;aacute;fico ha ganado en superficie de dibujo, pero los indicadores de la leyenda han quedado colocados en orden inverso a las barras. Para solucionar este problema haremos clic en el bot&amp;oacute;n de campos de la leyenda (Sexo_DS), de forma que despleguemos sus opciones de filtro, donde seleccionaremos &amp;quot;Ordenar de Z a A&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_35.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Con esta acci&amp;oacute;n, los indicadores de leyenda quedar&amp;aacute;n colocados adecuadamente, pero ahora nos encontraremos con el inconveniente de que los colores de las barras han quedado invertidos, y hemos perdido el borde de las barras del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;Restauraremos los bordes de las barras en la manera explicada anteriormente, mientras que en cuanto a los colores, para cada lado de la pir&amp;aacute;mide haremos clic derecho en una de las barras, y en la opci&amp;oacute;n &amp;quot;Relleno de forma&amp;quot;, cambiaremos el color actual por el que originalmente ten&amp;iacute;a el gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_36.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para completar los ajustes que estamos realizando sobre la leyenda, arrastraremos &amp;eacute;sta hasta que quede situada al nivel del elemento superior de la pir&amp;aacute;mide, y aumentaremos su anchura, para que los indicadores queden m&amp;aacute;s separados.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Despejar el &amp;aacute;rea de campos y agregar t&amp;iacute;tulo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Seguidamente haremos clic derecho en cualquiera de los botones de campos del gr&amp;aacute;fico y seleccionaremos la opci&amp;oacute;n &amp;quot;Ocultar todos los botones de campos en gr&amp;aacute;fico&amp;quot;. Con este movimiento impediremos que el usuario aplique filtros sobre el eje horizontal y/o vertical de la pir&amp;aacute;mide, manteniendo su estructura consistente y evitando as&amp;iacute; la posibilidad, por ejemplo, de ocultar rangos de edad o alguno de los sexos. No obstante, seguir&amp;aacute; existiendo tal posibilidad de filtro 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.201108/PiramidesPoblacionPowerPivot_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;Por otra parte, en el grupo de fichas &amp;quot;Herramientas del gr&amp;aacute;fico din&amp;aacute;mico&amp;quot; haremos clic en la ficha &amp;quot;Presentaci&amp;oacute;n&amp;quot;, y dentro del grupo &amp;quot;Etiquetas&amp;quot; haremos clic en la opci&amp;oacute;n &amp;quot;T&amp;iacute;tulo del gr&amp;aacute;fico&amp;quot;, que desplegar&amp;aacute; una serie de elementos entre los que elegiremos &amp;quot;Encima del gr&amp;aacute;fico&amp;quot;, a&amp;ntilde;adi&amp;eacute;ndose un cuadro de texto al gr&amp;aacute;fico, que editaremos para asignarle un t&amp;iacute;tulo. Llegados a este punto habremos completado el desarrollo de nuestra pir&amp;aacute;mide de poblaci&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.201108/PiramidesPoblacionPowerPivot_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;&lt;b&gt;Dinamizando los datos de la pir&amp;aacute;mide mediante segmentaciones&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Aunque hemos logrado el objetivo propuesto de crear una pir&amp;aacute;mide de poblaci&amp;oacute;n, resultar&amp;iacute;a interesante dotarla de cierto valor a&amp;ntilde;adido, tal y como vamos a hacer en este apartado.&lt;/p&gt;
&lt;p&gt;Si observamos el modelo de datos en la ventana de PowerPivot, caeremos en la cuenta de que todav&amp;iacute;a no hemos hecho uso de la informaci&amp;oacute;n que sobre zonificaci&amp;oacute;n sanitaria existe en el mismo, por lo que podemos aprovechar estos datos para construir un filtro que muestre la pir&amp;aacute;mide en base a la poblaci&amp;oacute;n de una o varias de estas zonas sanitarias.&lt;/p&gt;
&lt;p&gt;Las tablas din&amp;aacute;micas de PowerPivot, adem&amp;aacute;s del filtro tradicional, incorporan un nuevo tipo de filtro denominado &amp;quot;segmentaci&amp;oacute;n&amp;quot;, que adem&amp;aacute;s de la funcionalidad habitual de filtrado ofrece una interfaz de usuario m&amp;aacute;s flexible para la manipulaci&amp;oacute;n de los valores a tratar.&lt;/p&gt;
&lt;p&gt;Vamos a crear en nuestra pir&amp;aacute;mide una segmentaci&amp;oacute;n basada en la informaci&amp;oacute;n de zona. Para ello, en el panel de la lista de campos, arrastraremos el campo Zona_DS de la tabla Zona hasta el bloque &amp;quot;Segmentaciones de datos horizontales&amp;quot;, obteniendo como resultado una segmentaci&amp;oacute;n situada encima de la tabla din&amp;aacute;mica y el gr&amp;aacute;fico de pir&amp;aacute;mide.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_40.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para filtrar los datos mediante la segmentaci&amp;oacute;n simplemente tenemos que seleccionar el nombre de la zona sanitaria que queramos emplear como filtro. Tambi&amp;eacute;n es posible filtrar simult&amp;aacute;neamente varias zonas manteniendo pulsada la tecla Ctrl, mientras vamos haciendo clic en las zonas a filtrar (como muestra la siguiente figura). Si queremos eliminar todos los filtros activos haremos clic en el icono situado a tal efecto en la parte superior derecha de la segmentaci&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.201108/PiramidesPoblacionPowerPivot_5F00_41.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 finalizado el art&amp;iacute;culo, en el que a lo largo de sus dos entregas hemos mostrado el modo de construir una pir&amp;aacute;mide de poblaci&amp;oacute;n en Excel 2010, utilizando PowerPivot como herramienta de gesti&amp;oacute;n de los datos poblacionales. No obstante, la potencia de esta tecnolog&amp;iacute;a va m&amp;aacute;s all&amp;aacute; del mero tratamiento de la informaci&amp;oacute;n demogr&amp;aacute;fica, abarcando su campo de acci&amp;oacute;n a cualquier entorno en el que tengamos que realizar un an&amp;aacute;lisis con elevados vol&amp;uacute;menes de datos.&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=199789" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /><category term="DAX" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx" /></entry><entry><title>Pirámides de población con PowerPivot. Preparación del entorno de datos (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/08/18/pir-225-mides-de-poblaci-243-n-con-powerpivot-preparaci-243-n-del-entorno-de-datos-1.aspx" /><id>/blogs/lmblanco/archive/2011/08/18/pir-225-mides-de-poblaci-243-n-con-powerpivot-preparaci-243-n-del-entorno-de-datos-1.aspx</id><published>2011-08-18T19:13:00Z</published><updated>2011-08-18T19:13:00Z</updated><content type="html">&lt;p&gt;Una pir&amp;aacute;mide poblacional es una herramienta que nos permite analizar el estado y evoluci&amp;oacute;n de una poblaci&amp;oacute;n en funci&amp;oacute;n de su edad y sexo. Se trata de un elemento caracter&amp;iacute;stico en demograf&amp;iacute;a y estad&amp;iacute;stica, aunque sus aplicaciones tambi&amp;eacute;n abarcan campos tales como el sanitario, educativo, comercial, etc. Es por ello, que su integraci&amp;oacute;n en un sistema de informaci&amp;oacute;n perteneciente a alguna de las &amp;aacute;reas reci&amp;eacute;n mencionadas, supone un enriquecimiento sustancial en la calidad de los resultados obtenidos por los usuarios de tales sistemas.&lt;/p&gt;
&lt;p&gt;En el presente art&amp;iacute;culo abordaremos la construcci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n utilizando PowerPivot, un complemento para Excel 2010, que permite el acceso a or&amp;iacute;genes de datos de gran volumen, as&amp;iacute; como su posterior manejo y an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;Como ya apunt&amp;aacute;bamos en el art&amp;iacute;culo &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/07/18/generaci-243-n-de-datos-demogr-225-ficos-desde-sql-server.aspx"&gt;Generaci&amp;oacute;n de datos demogr&amp;aacute;ficos desde SQL Server&lt;/a&gt;, publicado en este mismo blog, nuestro objetivo actual (utilizando la base de datos PiramidePoblacion creada en el mencionado art&amp;iacute;culo) consistir&amp;aacute; en construir un gr&amp;aacute;fico que &amp;nbsp;represente una pir&amp;aacute;mide de poblaci&amp;oacute;n similar a la que vemos&amp;nbsp; en la siguiente figura.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_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;La primera parte del art&amp;iacute;culo estar&amp;aacute; dedicada a la preparaci&amp;oacute;n del modelo de datos de PowerPivot: conexi&amp;oacute;n contra un origen de datos, carga y creaci&amp;oacute;n de una tabla din&amp;aacute;mica para analizar las cifras de poblaci&amp;oacute;n. La segunda parte la destinaremos a la construcci&amp;oacute;n del gr&amp;aacute;fico que represente a la pir&amp;aacute;mide de poblaci&amp;oacute;n, partiendo de los datos sobre los que hemos trabajado en la primera entrega.&lt;/p&gt;
&lt;p&gt;Al igual que en el art&amp;iacute;culo mencionado anteriormente, quiero agradecer nuevamente a los integrantes del Servicio de Informes de Salud y Estudios (Subdirecci&amp;oacute;n de Promoci&amp;oacute;n de la Salud y Prevenci&amp;oacute;n, DG Atenci&amp;oacute;n Primaria, Consejer&amp;iacute;a Sanidad CM): Jenaro Astray Mochales, Mar&amp;iacute;a Felicitas Dom&amp;iacute;nguez Berj&amp;oacute;n, Mar&amp;iacute;a Dolores Esteban Vasallo, Beatriz Elvira Rodr&amp;iacute;guez y en especial a Ricard G&amp;egrave;nova Maleras, el soporte y orientaci&amp;oacute;n recibido sobre los conceptos demogr&amp;aacute;ficos necesarios con los que poder desarrollar apropiadamente una pir&amp;aacute;mide de poblaci&amp;oacute;n utilizando Excel 2010 en combinaci&amp;oacute;n con PowerPivot. Adem&amp;aacute;s de todo esto, Ricard ha accedido muy gustosamente a realizar una estupenda labor de revisi&amp;oacute;n de este art&amp;iacute;culo, con lo que el agradecimiento va por partida doble.&lt;/p&gt;
&lt;p&gt;Igualmente quisiera expresar mi agradecimiento a Enrique Barcel&amp;oacute; por todos sus estupendos trucos sobre desarrollo OLAP, que comparte con el equipo de trabajo, y que hacen un poco m&amp;aacute;s f&amp;aacute;cil nuestra labor de desarrollo en estas tareas del Business Intelligence.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Un poco de teor&amp;iacute;a&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero antes de entrar de lleno en su proceso de creaci&amp;oacute;n, vamos a proporcionar unos breves apuntes te&amp;oacute;ricos sobre las pir&amp;aacute;mides de poblaci&amp;oacute;n, que nos permitan entender mejor cu&amp;aacute;les son sus principales caracter&amp;iacute;sticas y la informaci&amp;oacute;n que de ellas podemos obtener y analizar.&lt;/p&gt;
&lt;p&gt;En esencia, una pir&amp;aacute;mide de poblaci&amp;oacute;n es un doble histograma que representa la distribuci&amp;oacute;n por edad y sexo de los efectivos de una poblaci&amp;oacute;n, bien en cifras absolutas, bien como porcentaje sobre la poblaci&amp;oacute;n total.&lt;/p&gt;
&lt;p&gt;Si estamos interesados en obtener una informaci&amp;oacute;n m&amp;aacute;s detallada acerca de los aspectos conceptuales que rodean a las pir&amp;aacute;mides de poblaci&amp;oacute;n, la ayuda del programa &lt;a href="http://www.sergas.es/MostrarContidos_N3_T01.aspx?IdPaxina=62714"&gt;Epidat 4.0&lt;/a&gt; puede resultarnos de utilidad. Se trata de una aplicaci&amp;oacute;n desarrollada por la &lt;a href="http://www.sergas.es/MostrarContidos_N3_T01.aspx?IdPaxina=62713"&gt;Consejer&amp;iacute;a de Sanidad de la Xunta de Galicia&lt;/a&gt; y la &lt;a href="http://new.paho.org/blogs/esp/?p=694"&gt;Organizaci&amp;oacute;n Panamericana de la Salud&lt;/a&gt; (OPS, Washington), de cuya documentaci&amp;oacute;n citamos a continuaci&amp;oacute;n algunos de los puntos m&amp;aacute;s importantes en relaci&amp;oacute;n con el tema que nos ocupa. En primer lugar comenzaremos con algunas nociones relativas a la construcci&amp;oacute;n de la pir&amp;aacute;mide de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;quot;El mejor modo de visualizar la distribuci&amp;oacute;n por sexo y edad de una poblaci&amp;oacute;n es, sin duda, la pir&amp;aacute;mide de poblaci&amp;oacute;n, verdadero icono de la demograf&amp;iacute;a. Una pir&amp;aacute;mide es un doble histograma que permite, con un solo golpe de vista, hacerse una idea clara no s&amp;oacute;lo acerca de las caracter&amp;iacute;sticas generales de la poblaci&amp;oacute;n (joven, envejecida, con alg&amp;uacute;n desequilibrio en funci&amp;oacute;n del sexo) sino tambi&amp;eacute;n sobre particularidades espec&amp;iacute;ficas que remiten a alg&amp;uacute;n acontecimiento concreto concerniente a la poblaci&amp;oacute;n objeto de estudio.&lt;/p&gt;
&lt;p&gt;Usualmente las pir&amp;aacute;mides de poblaci&amp;oacute;n se construyen siguiendo varias convenciones y reglas:&lt;/p&gt;
&lt;p&gt;- representar a los hombres a la izquierda y a las mujeres a la derecha del eje central,&lt;/p&gt;
&lt;p&gt;- ubicar las edades de manera que cuanto m&amp;aacute;s bajas sean, m&amp;aacute;s cerca est&amp;eacute;n de la base y viceversa,&lt;/p&gt;
&lt;p&gt;- mantener cierta proporcionalidad entre base y altura (3 anchuras por 2 alturas, o 4 por 3, aproximadamente),&lt;/p&gt;
&lt;p&gt;- respetar la misma escala a ambos lados del eje central (para favorecer la comparaci&amp;oacute;n entre sexos),&lt;/p&gt;
&lt;p&gt;- representar el peso de cada intervalo etario por la superficie de cada barra del histograma, no por su longitud, algo especialmente importante cuando se trabaja con grupos de edad desiguales,&lt;/p&gt;
&lt;p&gt;- pueden construirse con valores absolutos, pero es preferible hacerlo con las proporciones de cada edad y sexo respecto de la poblaci&amp;oacute;n total. &lt;/p&gt;
&lt;p&gt;El &amp;uacute;ltimo punto es importante y diferencia a la pir&amp;aacute;mide de los indicadores de estructura [proporci&amp;oacute;n de j&amp;oacute;venes o ancianos, &amp;iacute;ndice de envejecimiento, etc.], que se calculan separadamente sobre el total de cada sexo respectivo. En el caso de la pir&amp;aacute;mide de poblaci&amp;oacute;n, usar como denominador de las proporciones a la poblaci&amp;oacute;n total de ambos sexos reunidos garantiza la comparabilidad no s&amp;oacute;lo de la distribuci&amp;oacute;n por edad, sino tambi&amp;eacute;n por sexo&amp;quot;.&lt;/p&gt;
&lt;p&gt;Y finalizaremos con aquellas cuestiones relacionadas con la interpretaci&amp;oacute;n de la pir&amp;aacute;mide.&lt;/p&gt;
&lt;p&gt;&amp;quot;Una pir&amp;aacute;mide por sexo y edad resume la historia demogr&amp;aacute;fica de una poblaci&amp;oacute;n de por lo menos los cien a&amp;ntilde;os anteriores a la fecha de referencia (el tiempo que tarda, aproximadamente, una generaci&amp;oacute;n en pasar de la base a la cima de la pir&amp;aacute;mide). En ocasiones, el efecto indirecto de algunos acontecimientos demogr&amp;aacute;ficos es visible m&amp;aacute;s all&amp;aacute; de ese salto de un siglo (por ejemplo, el impacto del profundo descenso de la fecundidad de las &amp;uacute;ltimas d&amp;eacute;cadas experimentado por muchas poblaciones se apreciar&amp;aacute;, sin duda, en las pir&amp;aacute;mides de la primera mitad del siglo XXII). Una pir&amp;aacute;mide por edades simples [edad por edad: 0, 1, 2, 3 ... 99, 100 ...] permite un an&amp;aacute;lisis m&amp;aacute;s preciso que otra realizada por grupos de edades agregadas (quinquenales, decenales), pero corre tambi&amp;eacute;n el riesgo de verse afectada por problemas de calidad de los registros, o ser vulnerable a la inestabilidad de las distribuciones en poblaciones peque&amp;ntilde;as.&lt;/p&gt;
&lt;p&gt;La primera percepci&amp;oacute;n de una pir&amp;aacute;mide permite identificar los rasgos generales de la poblaci&amp;oacute;n representada: una pir&amp;aacute;mide de base ancha y que se estrecha r&amp;aacute;pidamente da idea de una poblaci&amp;oacute;n joven, con una alta proporci&amp;oacute;n de ni&amp;ntilde;os y adolescentes, y baja de adultos y ancianos, resultado de una alta natalidad y mortalidad. Inversamente, una pir&amp;aacute;mide con perfil estrecho en la base y ancho en el centro y la cima representa una estructura madura o envejecida. Cuanto mayor es la esperanza de vida de una poblaci&amp;oacute;n, mayor suele ser la desigualdad por sexo en la cima de la pir&amp;aacute;mide (m&amp;aacute;s llena por el lado de las mujeres, por su mayor nivel de supervivencia).&lt;/p&gt;
&lt;p&gt;La pir&amp;aacute;mide no da respuestas por s&amp;iacute; misma, sino que propicia que se planteen preguntas pertinentes. Las explicaciones para su perfil deben buscarse en la historia, en los avatares sociales, pol&amp;iacute;ticos, econ&amp;oacute;micos, que generan consecuencias en el devenir demogr&amp;aacute;fico -es decir, en la fecundidad, la mortalidad o la migraci&amp;oacute;n, que son los fen&amp;oacute;menos que modelan el contorno y fijan el tama&amp;ntilde;o de una poblaci&amp;oacute;n- y que tienen una interpretaci&amp;oacute;n en funci&amp;oacute;n de la triple perspectiva temporal: edad, periodo y cohorte&amp;quot;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Incorporando los datos a PowerPivot&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Gracias a VertiPaq, el motor de procesamiento de datos de PowerPivot, podemos conseguir una potencia y velocidad sin precedentes en la manipulaci&amp;oacute;n, filtrado, creaci&amp;oacute;n de expresiones de l&amp;oacute;gica de negocio, y en definitiva, en todas aquellas operaciones anal&amp;iacute;ticas que debamos realizar sobre un modelo de datos creado con esta herramienta.&lt;/p&gt;
&lt;p&gt;El siguiente &lt;a href="http://www.powerpivot.com/"&gt;enlace&lt;/a&gt; proporciona acceso a la p&amp;aacute;gina principal de PowerPivot, desde donde podremos descargarlo, para posteriormente instalarlo en nuestra m&amp;aacute;quina, de forma que podamos seguir los ejemplos del art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;Una vez que hayamos instalado PowerPivot iniciaremos Excel 2010, cre&amp;aacute;ndose una nueva hoja de c&amp;aacute;lculo a la que daremos el nombre PiramidePoblacion.xlsx. En la cinta de opciones dispondremos ahora de una nueva ficha con el nombre &amp;quot;PowerPivot&amp;quot;. Al hacer clic en la misma seleccionaremos la opci&amp;oacute;n &amp;quot;Ventana de PowerPivot&amp;quot;, perteneciente al grupo &amp;quot;Iniciar&amp;quot;, lo que abrir&amp;aacute; la mencionada ventana de trabajo de PowerPivot, en la que definiremos la estructura de tablas que vamos a utilizar, o &amp;quot;modelo de datos&amp;quot;, tal y c&amp;oacute;mo se denomina dentro del contexto de PowerPivot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n, en la pesta&amp;ntilde;a &amp;quot;P&amp;aacute;gina principal&amp;quot; de la ventana de PowerPivot, nos conectaremos a la base de datos mediante la opci&amp;oacute;n &amp;quot;Desde base de datos | De SQL Server&amp;quot;, situada en el grupo &amp;quot;Obtener datos externos&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta acci&amp;oacute;n iniciar&amp;aacute; el asistente para importar tablas, en el que indicaremos el origen de datos al que nos queremos conectar.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una fuente de datos v&amp;aacute;lida para elaborar una pir&amp;aacute;mide de poblaci&amp;oacute;n ha de tener como m&amp;iacute;nimo informaci&amp;oacute;n acerca del sexo y edad de la poblaci&amp;oacute;n, como es el caso de nuestra base de datos PiramidePoblacion. Adicionalmente, y como forma de enriquecer el an&amp;aacute;lisis a realizar, la base de datos puede disponer de informaci&amp;oacute;n complementaria como pudiera ser la zonificaci&amp;oacute;n sanitaria, nacionalidad de la poblaci&amp;oacute;n, etc.&lt;/p&gt;
&lt;p&gt;Tras elegir la base de datos PiramidePoblacion, el siguiente paso nos ofrecer&amp;aacute; una lista de las tablas y vistas que podremos importar, donde marcaremos las siguientes: Edad, Poblaci&amp;oacute;n, Sexo y Zona, comenzando la importaci&amp;oacute;n al hacer clic en el bot&amp;oacute;n &amp;quot;Finalizar&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si la importaci&amp;oacute;n se desarrolla correctamente, el asistente mostrara una ventana resumen del proceso.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez terminada la incorporaci&amp;oacute;n de datos haremos clic en &amp;quot;Cerrar&amp;quot; para volver a la ventana de PowerPivot, donde hallaremos organizadas en diversas pesta&amp;ntilde;as cada una de las tablas importadas.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_07.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;An&amp;aacute;lisis mediante tabla din&amp;aacute;mica&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Antes de pasar a la fase de construcci&amp;oacute;n de la pir&amp;aacute;mide de poblaci&amp;oacute;n, vamos a utilizar una tabla din&amp;aacute;mica de PowerPivot para analizar las cifras del modelo de datos, por lo que situados en su ventana de trabajo haremos clic en la opci&amp;oacute;n &amp;quot;PivotTable&amp;quot;, perteneciente al grupo &amp;quot;Informes&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Esta acci&amp;oacute;n nos posicionar&amp;aacute; en la ventana de Excel, donde se abrir&amp;aacute; un di&amp;aacute;logo en el que elegiremos la hoja de c&amp;aacute;lculo en la que se ubicar&amp;aacute; la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En nuestro caso seleccionaremos la primera opci&amp;oacute;n y aceptaremos el di&amp;aacute;logo, cre&amp;aacute;ndose la tabla din&amp;aacute;mica en una nueva hoja c&amp;aacute;lculo&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_10.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_10.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Desde el panel &amp;quot;Lista de campos de PowerPivot&amp;quot; tenemos a nuestra disposici&amp;oacute;n los campos de las tablas del modelo de datos, que situaremos en las diferentes zonas de la tabla din&amp;aacute;mica (etiquetas de filas, columnas, valores, etc.) para llevar a cabo nuestras operaciones de an&amp;aacute;lisis. Utilizaremos para ello un estilo de trabajo muy semejante al que emplear&amp;iacute;amos si estuvi&amp;eacute;ramos consultando un cubo OLAP, ya que el manejo de los campos de PowerPivot en este sentido es similar al que podemos realizar con las dimensiones y medidas de un cubo de datos cuando es consultado desde Excel.&lt;/p&gt;
&lt;p&gt;Vamos a comenzar por una consulta sencilla, consistente en contar los registros de la tabla Poblaci&amp;oacute;n, agrupando la informaci&amp;oacute;n por rangos de edad, los cuales situaremos en las filas de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;El recuento de registros lo realizaremos mediante una expresi&amp;oacute;n &lt;a href="http://social.technet.microsoft.com/wiki/contents/articles/powerpivot-data-analysis-expressions-dax-language.aspx"&gt;DAX&lt;/a&gt; (el lenguaje de consultas de PowerPivot) situada en una medida calculada, que crearemos seleccionando la opci&amp;oacute;n &amp;quot;Nueva medida&amp;quot;, perteneciente al grupo &amp;quot;Medidas&amp;quot; de la ficha &amp;quot;PowerPivot&amp;quot;. Esta medida la aplicaremos sobre la tabla Poblaci&amp;oacute;n, por lo que deberemos estar previamente posicionados en la misma, dentro del panel de la lista de campos.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_11.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_11.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Al seleccionar esta opci&amp;oacute;n se abrir&amp;aacute; la ventana &amp;quot;Configuraci&amp;oacute;n de medida&amp;quot;, en la que dentro del cuadro de texto reservado para la f&amp;oacute;rmula escribiremos la siguiente expresi&amp;oacute;n:&lt;/p&gt;
&lt;p&gt;=COUNTROWS(Poblacion)&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n COUNTROWS, como su nombre indica, cuenta las filas de la tabla pasada como par&amp;aacute;metro. Para terminar la creaci&amp;oacute;n de nuestra medida le daremos el nombre &amp;quot;RecuentoPoblacion&amp;quot; y haremos clic en &amp;quot;Aceptar&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_12.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_12.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Nada m&amp;aacute;s terminar de crear la medida, &amp;eacute;sta se a&amp;ntilde;adir&amp;aacute; autom&amp;aacute;ticamente a la lista de campos de la tabla Poblaci&amp;oacute;n y al bloque &amp;quot;Valores&amp;quot;, visualiz&amp;aacute;ndose en la tabla din&amp;aacute;mica el n&amp;uacute;mero total de filas de la tabla.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_13.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_13.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n seleccionaremos, en el panel de la lista de campos, el campo Edad_Grupo de la tabla Edad, lo que situar&amp;aacute; autom&amp;aacute;ticamente al mencionado campo en el bloque &amp;quot;Etiquetas de fila&amp;quot;. Si este no fuera el comportamiento obtenido, arrastraremos manualmente el campo hasta colocarlo en dicho bloque.&lt;/p&gt;
&lt;p&gt;Como consecuencia de la acci&amp;oacute;n anterior la tabla din&amp;aacute;mica se ver&amp;aacute; actualizada, mostr&amp;aacute;ndose en el eje de las filas los valores del campo Edad_Grupo. Respecto a las cifras de la medida RecuentoPoblacion, &amp;eacute;stas deber&amp;iacute;an repartirse entre los tramos de cada edad, para as&amp;iacute; reflejar el n&amp;uacute;mero de registros (poblaci&amp;oacute;n) correspondiente a cada uno de dichos tramos. Sin embargo, como vemos en la siguiente figura, es algo que no est&amp;aacute; ocurriendo, ya que la medida muestra el mismo valor para todas las filas, lo cual es incorrecto.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_14.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_14.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Relaciones entre las tablas del modelo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Observando el panel de campos vemos que PowerPivot ya se ha percatado del problema que acabamos de comentar, porque en la parte superior de dicho panel aparece un aviso, que nos informa acerca de que puede ser necesaria una relaci&amp;oacute;n entre las tablas que se est&amp;aacute;n utilizando para componer la consulta de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;Este problema no habr&amp;iacute;a tenido lugar si hubiesen existido las oportunas relaciones entre las tablas de la base de datos, aunque como ya dijimos en el art&amp;iacute;culo sobre la creaci&amp;oacute;n de la base de datos de poblaci&amp;oacute;n, dichas relaciones no fueron creadas intencionadamente, para as&amp;iacute; demostrar que tambi&amp;eacute;n es posible hacerlo desde PowerPivot, como veremos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Para dejar que PowerPivot detecte autom&amp;aacute;ticamente la relaci&amp;oacute;n que necesita, haremos clic en el bot&amp;oacute;n &amp;quot;Crear&amp;quot; que aparece junto al aviso mostrado en el panel de campos. Como resultado se abrir&amp;aacute; una ventana encargada de crear la oportuna relaci&amp;oacute;n, ofreci&amp;eacute;ndonos informaci&amp;oacute;n adicional sobre la misma a trav&amp;eacute;s de los enlaces &amp;quot;Detalles&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_15.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_15.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez creada la relaci&amp;oacute;n, &amp;eacute;sta ser&amp;aacute; aplicada inmediatamente, sin intervenci&amp;oacute;n del usuario, sobre la tabla din&amp;aacute;mica, que de esta forma ya mostrar&amp;aacute; correctamente los valores de la medida agrupados por edad.&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n es posible crear manualmente las relaciones entre las tablas del modelo de datos utilizando la ventana de trabajo de PowerPivot. Para ello haremos clic en la opci&amp;oacute;n &amp;quot;Crear relaci&amp;oacute;n&amp;quot;, perteneciente al grupo &amp;quot;Relaciones&amp;quot;, que est&amp;aacute; situado en la ficha &amp;quot;Dise&amp;ntilde;o&amp;quot; de la mencionada ventana.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_16.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_16.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta opci&amp;oacute;n abrir&amp;aacute; una ventana con el mismo nombre, en la que seleccionaremos la tabla y columna que representar&amp;aacute;n el origen y destino de la relaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_17.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_17.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma estableceremos dos nuevas relaciones, que tendr&amp;aacute;n a la tabla Poblaci&amp;oacute;n como origen y a las tablas Sexo y Zona como destino. Adicionalmente, desde la opci&amp;oacute;n &amp;quot;Administrar relaciones&amp;quot; podemos ver un resumen de las relaciones creadas as&amp;iacute; como gestionarlas (crear, editar, eliminar, etc.).&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_18.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_18.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Estos cambios que acabamos de realizar en la ventana de PowerPivot pueden afectar directa o indirectamente a los datos que estamos presentando en la tabla din&amp;aacute;mica; por dicho motivo, al retornar a la ventana de Excel veremos un aviso al respecto en el panel de campos, donde haremos clic en el bot&amp;oacute;n &amp;quot;Actualizar&amp;quot;, para refrescar los datos con los que estamos trabajando.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_19.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_19.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Agregando datos en el eje de columnas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Solucionado el problema de las relaciones, ahora es el momento de a&amp;ntilde;adir nuevos datos en las columnas de la tabla din&amp;aacute;mica mediante el campo Sexo_DS de la tabla Sexo.&lt;/p&gt;
&lt;p&gt;Al&amp;nbsp; ser seleccionado, este campo se situar&amp;aacute; por defecto en el bloque &amp;quot;Etiquetas de fila&amp;quot;, de modo que tendremos que moverlo manualmente hasta el bloque &amp;quot;Etiquetas de columna&amp;quot;; o bien al hacer clic en &amp;eacute;l lo arrastraremos directamente hasta el bloque de etiquetas de columna.&lt;/p&gt;
&lt;p&gt;Adicionalmente, daremos formato a las celdas num&amp;eacute;ricas haciendo clic derecho en cualquiera de ellas y seleccionando la opci&amp;oacute;n &amp;quot;Formato de n&amp;uacute;mero&amp;quot;, en el cuadro de di&amp;aacute;logo de formato definiremos &amp;eacute;ste sin decimales y con separador de miles.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_20.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_20.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez realizadas estas operaciones, la tabla din&amp;aacute;mica ya mostrar&amp;aacute; los datos de poblaci&amp;oacute;n de manera acorde a los requerimientos planteados.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_21.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_21.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Llegados a este punto concluimos la primera parte del art&amp;iacute;culo. En la siguiente entrega alcanzaremos nuestro objetivo de crear un gr&amp;aacute;fico que represente la pir&amp;aacute;mide de poblaci&amp;oacute;n utilizando los datos que hemos preparado con PowerPivot.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=199678" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="DAX" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/DAX/default.aspx" /></entry><entry><title>Generación de datos demográficos desde SQL Server</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/07/18/generaci-243-n-de-datos-demogr-225-ficos-desde-sql-server.aspx" /><id>/blogs/lmblanco/archive/2011/07/18/generaci-243-n-de-datos-demogr-225-ficos-desde-sql-server.aspx</id><published>2011-07-18T20:25:00Z</published><updated>2011-07-18T20:25:00Z</updated><content type="html">&lt;p&gt;Con motivo de un pr&amp;oacute;ximo art&amp;iacute;culo que dedicaremos a la elaboraci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n desde PowerPivot, nos hemos encontrado recientemente ante la tesitura de desarrollar un proceso para crear una base de datos con informaci&amp;oacute;n demogr&amp;aacute;fica, que sirva como punto de partida para la construcci&amp;oacute;n del modelo de datos en PowerPivot.&lt;/p&gt;
&lt;p&gt;A diferencia del art&amp;iacute;culo &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/04/26/generar-datos-de-prueba-para-sql-server-desde-excel-operaciones-desde-excel-1.aspx"&gt;Generar datos de prueba para SQL Server desde Excel&lt;/a&gt;, publicado anteriormente en este mismo blog, donde utiliz&amp;aacute;bamos Excel para generar datos ficticios, tambi&amp;eacute;n de poblaci&amp;oacute;n, en esta ocasi&amp;oacute;n trabajaremos con datos reales, los cuales representan un mayor volumen de informaci&amp;oacute;n a manejar con respecto al mencionado art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;El objetivo del presente art&amp;iacute;culo consistir&amp;aacute; en crear una base de datos que contenga una tabla de poblaci&amp;oacute;n, en la que cada registro represente a un individuo, con su correspondiente edad, sexo y zona de atenci&amp;oacute;n sanitaria.&lt;/p&gt;
&lt;p&gt;Antes de proseguir, quisiera expresar mi agradecimiento a Ricard G&amp;egrave;nova Maleras, dem&amp;oacute;grafo especializado en an&amp;aacute;lisis poblacionales sanitarios, perteneciente al Servicio de Informes de Salud y Estudios (Subdirecci&amp;oacute;n de Promoci&amp;oacute;n de la Salud y Prevenci&amp;oacute;n, DG Atenci&amp;oacute;n Primaria, Consejer&amp;iacute;a Sanidad CM), por su valioso asesoramiento en aquellos aspectos demogr&amp;aacute;ficos esenciales para la elaboraci&amp;oacute;n de &amp;eacute;ste y el pr&amp;oacute;ximo art&amp;iacute;culo sobre pir&amp;aacute;mides de poblaci&amp;oacute;n, as&amp;iacute; como al resto de integrantes del mencionado Servicio: Jenaro Astray Mochales, Mar&amp;iacute;a Felicitas Dom&amp;iacute;nguez Berj&amp;oacute;n, Mar&amp;iacute;a Dolores Esteban Vasallo y Beatriz Elvira Rodr&amp;iacute;guez, por su apoyo y ayuda en el resto de conceptos sanitarios relacionados con poblaciones, necesarios para el adecuado enfoque de este art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;Por &amp;uacute;ltimo, aunque no menos importante, agradezco a Enrique Barcel&amp;oacute;, compa&amp;ntilde;ero de fatigas en estas labores del Business Intelligence, los interesantes ratos que pasamos departiendo acerca de los aspectos relacionados con el desarrollo de sistemas de informaci&amp;oacute;n en general, y sobre cubos de datos en particular, as&amp;iacute; como por compartir conmigo sus asombrosos conocimientos sobre OLAP.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Obtenci&amp;oacute;n y preparaci&amp;oacute;n de los datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Existe un importante n&amp;uacute;mero de sitios Web, pertenecientes a diversos organismos, donde encontraremos la informaci&amp;oacute;n demogr&amp;aacute;fica necesaria para realizar nuestros an&amp;aacute;lisis, organizada por criterios tales como sexo, edad, regi&amp;oacute;n geogr&amp;aacute;fica, etc. De todos estos organismos destacaremos los correspondientes a &lt;a href="http://esa.un.org/unpd/wpp/Excel-Data/population.htm"&gt;Naciones Unidas&lt;/a&gt;, &lt;a href="http://www.ine.es/inebmenu/mnu_cifraspob.htm"&gt;Instituto Nacional de Estad&amp;iacute;stica&lt;/a&gt; (Espa&amp;ntilde;a), &lt;a href="http://www.madrid.org/iestadis/fijas/estructu/demograficas/padron/estructupc.htm"&gt;Instituto de Estad&amp;iacute;stica de la CM&lt;/a&gt; (Madrid) y &lt;a href="http://www.eclac.org/celade/proyecciones/basedatos_BD.htm"&gt;CELADE&lt;/a&gt; (datos demogr&amp;aacute;ficos de Am&amp;eacute;rica Latina y Caribe). En todos ellos, adem&amp;aacute;s de la consulta directa en la propia web, disponemos de la posibilidad de descargar la informaci&amp;oacute;n en diversos formatos tales como Excel, CSV, etc.&lt;/p&gt;
&lt;p&gt;Para el desarrollo de los ejemplos de este art&amp;iacute;culo utilizaremos los datos del padr&amp;oacute;n de poblaci&amp;oacute;n de la Comunidad de Madrid correspondientes al a&amp;ntilde;o 2010, clasificados por edad, sexo y la nueva zonificaci&amp;oacute;n sanitaria, vigente a partir de dicho a&amp;ntilde;o, que se encuentran en el siguiente &lt;a href="http://www.madrid.org/iestadis/fijas/estructu/demograficas/padron/pc10i5z10.htm"&gt;enlace&lt;/a&gt; (T10Z2_SALUD10) de la p&amp;aacute;gina web del Instituto de Estad&amp;iacute;stica de la CM.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Estrategia para la extracci&amp;oacute;n de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;El archivo Excel pc10t10z2_salud10.xls, obtenido del anterior enlace, organiza los datos de poblaci&amp;oacute;n alrededor de tres hojas de c&amp;aacute;lculo que contienen, respectivamente, los valores de poblaci&amp;oacute;n totales, por hombres y mujeres.&lt;/p&gt;
&lt;p&gt;Cada hoja de c&amp;aacute;lculo tiene en sus dos primeras columnas el c&amp;oacute;digo y nombre de la zona de atenci&amp;oacute;n sanitaria, mientras que el resto de las columnas contienen las cifras de poblaci&amp;oacute;n clasificadas en agrupaciones quinquenales, donde para cada grupo existe una columna con el total quinquenal, y varias columnas que representan el desglose por edad simple de las edades que conforman el grupo.&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_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Los datos que necesitamos extraer son, por un lado, los c&amp;oacute;digos y nombres de la zonificaci&amp;oacute;n sanitaria, para lo que podemos usar cualquiera de las hojas de c&amp;aacute;lculo del archivo Excel. Por otra parte, tendremos que obtener el total quinquenal de cada grupo de edad, tanto de la hoja de poblaci&amp;oacute;n masculina como femenina.&lt;/p&gt;
&lt;p&gt;Todos estos valores los llevaremos a una nueva hoja de c&amp;aacute;lculo en la que copiaremos cada combinaci&amp;oacute;n de c&amp;oacute;digos de zona sanitaria, grupo de edad y tipo de poblaci&amp;oacute;n (hombre/mujer) siguiendo un orden de pasos parecido al de la siguiente figura.&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 src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n observamos una aproximaci&amp;oacute;n de lo que ser&amp;iacute;a la hoja de c&amp;aacute;lculo resultante.&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 src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El empleo manual de las operaciones seleccionar, copiar y pegar, para traspasar los datos que necesitamos a una nueva hoja puede resultar una tarea muy laboriosa y pesada. Es por ello que proponemos el uso de una macro que automatice toda esta labor, lo que nos permitir&amp;aacute; repetir el proceso cuantas veces queramos, as&amp;iacute; como aplicarlo a otras poblaciones cuyos datos se encuentren estructurados de la misma forma.&lt;/p&gt;
&lt;p&gt;Para crear la macro, en la cinta de opciones de Excel haremos clic en la opci&amp;oacute;n &amp;quot;Macros&amp;quot;, perteneciente al grupo del mismo nombre situado en la ficha &amp;quot;Vista&amp;quot;.&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_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta opci&amp;oacute;n tambi&amp;eacute;n est&amp;aacute; disponible en la ficha &amp;quot;Programador&amp;quot; dentro del grupo &amp;quot;C&amp;oacute;digo&amp;quot;&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_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;En el caso de que la ficha &amp;quot;Programador&amp;quot; no est&amp;eacute; visible haremos clic en la ficha &amp;quot;Archivo&amp;quot;, y dentro de esta en &amp;quot;Opciones&amp;quot;. En la ventana &amp;quot;Opciones de Excel&amp;quot; haremos clic en &amp;quot;Personalizar cinta de opciones&amp;quot;, y desplegando la lista situada a la derecha seleccionaremos el elemento &amp;quot;Fichas principales&amp;quot;. Del panel situado debajo de la lista marcaremos la casilla &amp;quot;Programador&amp;quot;, lo que har&amp;aacute; visible esta ficha en la cinta de opciones.&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_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Independientemente del modo elegido para su creaci&amp;oacute;n, aparecer&amp;aacute; la ventana &amp;quot;Macro&amp;quot;, en la que daremos el nombre &amp;quot;TraspasarDatosPoblacion&amp;quot; a nuestra macro y haremos clic en &amp;quot;Crear&amp;quot;, lo que nos llevar&amp;aacute; al editor de VBA (Visual Basic for Applications), donde escribiremos el c&amp;oacute;digo de la macro.&lt;/p&gt;
&lt;p&gt;Vamos a dividir el trabajo que realizar&amp;aacute; la macro en tres partes: la creaci&amp;oacute;n de los datos para la columna de c&amp;oacute;digos de zona sanitaria; la columna de rangos de edad; y por &amp;uacute;ltimo, las columnas de cantidades de poblaci&amp;oacute;n por sexo.&lt;/p&gt;
&lt;p&gt;En el siguiente bloque de c&amp;oacute;digo podemos ver las instrucciones encargadas de crear una nueva hoja de c&amp;aacute;lculo, a la que asignaremos un nombre y los t&amp;iacute;tulos de columna. Posteriormente seleccionaremos los c&amp;oacute;digos de zona de una de las hojas origen, que pegaremos en la nueva hoja tantas veces como rangos de edad existan.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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; crear nueva hoja y asignarle nombre&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; asignar t&amp;iacute;tulos en columnas&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; volver a la hoja de datos origen&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; establecer fila inicial y final de datos&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; calcular cantidad de zonas existentes&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; c&amp;oacute;digos de zona&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; seleccionar c&amp;oacute;digos, copiarlos al portapapeles y pegarlos en nueva hoja&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; realizar el pegado por cada grupo de edad&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; obtener el siguiente n&amp;uacute;mero de fila vac&amp;iacute;o de la columna&lt;/span&gt;&lt;br /&gt;    nFilaVacia = FilaVaciaEnColumna(1)&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; posicionar en celda&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; pegar datos&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; asignar fondo color blanco a columna&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;br /&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Antes de cada operaci&amp;oacute;n de asignaci&amp;oacute;n de valores en las celdas, necesitamos conocer la fila vac&amp;iacute;a a partir de la que pegaremos los datos, para lo que utilizaremos la funci&amp;oacute;n auxiliar &amp;quot;FilaVaciaEnColumna&amp;quot;, que recorrer&amp;aacute; la colecci&amp;oacute;n de filas de la hoja hasta encontrar la fila que contiene una celda vac&amp;iacute;a en aquella columna sobre la que estamos operando.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La siguiente fase en la creaci&amp;oacute;n de la macro consistir&amp;aacute; en asignar los valores a la columna de rangos de edad. Para ello crearemos un array conteniendo dichos valores, y al recorrerlo, haremos que en cada iteraci&amp;oacute;n se copie el valor del rango en curso el mismo n&amp;uacute;mero de veces que la cantidad de zonas sanitarias existentes. Cabe destacar que antes de asignar los valores a esta columna le aplicaremos el formato texto (propiedad Selection.NumberFormat), ya que en caso contrario, el formato predeterminado puede hacer que algunos valores de los rangos de edad sean interpretados como mes-a&amp;ntilde;o.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39; rangos de edad&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; establecer el formato de la columna de edad a texto&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; repetir cada valor del array aRangosEdad&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; tantas veces como n&amp;uacute;mero de zonas existen&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; obtener el siguiente n&amp;uacute;mero de fila vac&amp;iacute;o de la columna&lt;/span&gt;&lt;br /&gt;    nFilaVacia = FilaVaciaEnColumna(2)&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; asignar el valor del rango de edad en las dos siguientes celdas hacia abajo&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; establecer el rango de celdas y rellenar con el valor de las anteriores celdas&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Y terminaremos la macro con la asignaci&amp;oacute;n de las columnas dedicadas a las cifras de poblaci&amp;oacute;n por sexo, donde esta vez utilizaremos dos arrays combinados, conteniendo las cabeceras de columna que corresponden a los totales quinquenales de poblaci&amp;oacute;n, y el tipo de poblaci&amp;oacute;n. Al recorrer ambos de forma anidada, iremos extrayendo, para un tipo de poblaci&amp;oacute;n determinado, sus cifras de individuos, asign&amp;aacute;ndolas a la hoja de c&amp;aacute;lculo destino.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39; cifras de poblaci&amp;oacute;n por sexo&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; por cada tipo de poblaci&amp;oacute;n&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; obtener la informaci&amp;oacute;n del tipo de poblaci&amp;oacute;n:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; sexo, columna destino, posici&amp;oacute;n num&amp;eacute;rica columna destino&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; recorrer las columnas que contienen las cifras de poblaci&amp;oacute;n&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; y pegarlas en la nueva hoja&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; posicionar en hoja con datos origen poblaci&amp;oacute;n&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; seleccionar celdas y copiarlas&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; posicionar en hoja destino de los datos&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; obtener siguiente fila vac&amp;iacute;a, posicionar en celda y pegar los datos&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; cambiar estilo de columnas para que se visualicen bordes de celdas&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Seguidamente crearemos una nueva macro con el nombre &amp;quot;TraspasarDatosZonificacion&amp;quot;, que trasladar&amp;aacute; a una nueva hoja del archivo Excel los c&amp;oacute;digos y nombres de las zonas de asistencia sanitaria. Estos datos servir&amp;aacute;n para cargar una de las tablas cat&amp;aacute;logo de la base de datos que crearemos m&amp;aacute;s adelante.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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; crear nueva hoja y asignarle nombre&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; poner t&amp;iacute;tulos de columna&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; volver a la hoja de datos&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; copiar c&amp;oacute;digos y nombres de zonas al portapapeles&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; volver a hoja destino y pegar los datos&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; quitar color de fondo de celdas&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Cuando copiamos los c&amp;oacute;digos y nombres de las zonas sanitarias a las nuevas hojas dentro del archivo Excel, tambi&amp;eacute;n se copia la configuraci&amp;oacute;n de colores de las celdas correspondientes a estos valores. Para conseguir que el color de fondo de estas celdas sea blanco utilizamos las siguientes l&amp;iacute;neas de c&amp;oacute;digo.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;Selection.Interior.TintAndShade = 0&lt;br /&gt;Selection.Interior.PatternTintAndShade = 0&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Pero si nuestra versi&amp;oacute;n de Excel es anterior a 2007 estas l&amp;iacute;neas producir&amp;aacute;n un error en tiempo de ejecuci&amp;oacute;n, por lo que deberemos comentarlas para evitar que sean ejecutadas.&lt;/p&gt;
&lt;p&gt;Finalmente, desde la ventana de administraci&amp;oacute;n de macros, seleccionaremos cada una y haremos clic en &amp;quot;Ejecutar&amp;quot;.&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_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como resultado obtendremos dos nuevas hojas con los datos generados por el c&amp;oacute;digo de las 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 src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_08.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de la base de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Nuestro pr&amp;oacute;ximo paso consistir&amp;aacute; en crear la base de datos PiramidePoblacion, que alojar&amp;aacute; la informaci&amp;oacute;n que acabamos de preparar en Excel. El siguiente bloque de c&amp;oacute;digo muestra el script de Transact-SQL que tendremos que ejecutar en nuestra instancia de SQL Server (la versi&amp;oacute;n utilizada en este art&amp;iacute;culo ha sido SQL Server 2008 R2).&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La tabla Poblaci&amp;oacute;n, como podemos adivinar por su nombre, ser&amp;aacute; la que contenga los datos principales de nuestra poblaci&amp;oacute;n, mientras que las tablas Zona, Edad y Sexo contendr&amp;aacute;n informaci&amp;oacute;n de cat&amp;aacute;logo (c&amp;oacute;digo/descriptor).&lt;/p&gt;
&lt;p&gt;Con toda seguridad, en el script habremos notado la carencia de claves ajenas entre la tabla Poblaci&amp;oacute;n y el resto. Se trata de un olvido intencionado, ya que en el pr&amp;oacute;ximo art&amp;iacute;culo sobre pir&amp;aacute;mides de poblaci&amp;oacute;n esto nos servir&amp;aacute; para demostrar c&amp;oacute;mo a trav&amp;eacute;s de PowerPivot tambi&amp;eacute;n es posible crear relaciones entre las tablas del modelo.&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s de ejecutar el script, la primera acci&amp;oacute;n que realizaremos en la nueva base de datos ser&amp;aacute; el volcado, desde el archivo pc10t10z2_salud10.xls, de la hoja de c&amp;aacute;lculo DatosBasePoblacion en la tabla del mismo nombre, utilizando la siguiente sentencia.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Generando los registros de poblaci&amp;oacute;n en la base de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La finalidad del proceso que estamos llevando a cabo hasta este momento consiste en generar, para la tabla Poblaci&amp;oacute;n, una cantidad de registros que represente a la poblaci&amp;oacute;n con la que vamos a trabajar, y que ser&amp;aacute; igual a la suma de las columnas Poblacion_H y Poblacion_M de la tabla 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 src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para tal volumen de datos, el uso de un bucle que vaya creando uno a uno los registros resulta totalmente inviable por cuestiones de tiempo y rendimiento, por lo que debemos buscar un sistema alternativo, que nos permita trabajar utilizando conjuntos de resultados, para poder crear la cantidad de registros que necesitamos empleando un reducido n&amp;uacute;mero de operaciones.&lt;/p&gt;
&lt;p&gt;La t&amp;eacute;cnica por la que vamos a decantarnos se muestra en el libro &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;, escrito por &lt;a href="http://tsql.solidq.com/index.htm"&gt;Itzik Ben-Gan&lt;/a&gt; junto a otros grandes nombres de SQL Server: Lubor Kollar, Dejan Sarka y Steve Kass; y consiste en utilizar varias &amp;quot;Expresiones Comunes de Tabla&amp;quot; o CTE (Common Table Expression) anidadas, mediante las cuales generaremos un conjunto de resultados del tama&amp;ntilde;o necesario, que combinaremos con una sentencia INSERT INTO, para a&amp;ntilde;adir a la tabla Poblaci&amp;oacute;n un n&amp;uacute;mero de registros determinado. Todo ello lo incluiremos en el siguiente procedimiento almacenado.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;@sZona_ID &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3),&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; @sZona_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;br /&gt;&lt;/div&gt;
&lt;p&gt;A continuaci&amp;oacute;n escribiremos un script en el que recorreremos la tabla DatosBasePoblacion, y por cada uno de sus registros tomaremos el valor de los campos Poblacion_H y Poblacion_M, insertando en la tabla Poblaci&amp;oacute;n, mediante la ejecuci&amp;oacute;n del procedimiento almacenado GenerarRegistrosPoblacion, un n&amp;uacute;mero de filas igual al valor de los mencionados campos.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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; @sZona &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3);&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; @sZona = 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; DatosBasePoblacion&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 @sZona, @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 @sZona, @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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;El tiempo empleado en la ejecuci&amp;oacute;n de este script ha sido de 1 minuto y 37 segundos en una m&amp;aacute;quina virtual dotada de una CPU Core 2 Duo y 1,5 GB de RAM, lo cual representa un excelente rendimiento, dado el elevado n&amp;uacute;mero de registros a&amp;ntilde;adidos a la tabla Poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Terminamos las operaciones de preparaci&amp;oacute;n de la base de datos con las sentencias utilizadas para a&amp;ntilde;adir datos en las tablas que actuar&amp;aacute;n como cat&amp;aacute;logos de la tabla Poblaci&amp;oacute;n. Como vemos a continuaci&amp;oacute;n, para la tabla Zona tambi&amp;eacute;n obtenemos los registros del archivo pc10t10z2_salud10.xls.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;--&lt;span style="color:#008000;"&gt;////&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;INSERT 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;    &lt;span style="color:#0000ff;"&gt;INSERT &lt;/span&gt;&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;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt; &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;&lt;span style="color:#0000ff;"&gt;INSERT &lt;/span&gt;&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Carga de datos completada&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Llegados a este punto podemos dar por finalizado el proceso de creaci&amp;oacute;n y carga de informaci&amp;oacute;n demogr&amp;aacute;fica en nuestra base de datos. Como hemos comentado al comienzo, en un pr&amp;oacute;ximo art&amp;iacute;culo utilizaremos esta base de datos como punto de partida para la construcci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n con PowerPivot.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=197962" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /></entry><entry><title>Generar datos de prueba para SQL Server desde Excel. El traspaso a SQL Server (y 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/04/28/generar-datos-de-prueba-para-sql-server-desde-excel-el-traspaso-a-sql-server-y-2.aspx" /><id>/blogs/lmblanco/archive/2011/04/28/generar-datos-de-prueba-para-sql-server-desde-excel-el-traspaso-a-sql-server-y-2.aspx</id><published>2011-04-28T18:30:00Z</published><updated>2011-04-28T18:30:00Z</updated><content type="html">&lt;p&gt;Despu&amp;eacute;s de la generaci&amp;oacute;n de datos realizada en Excel, que explicamos en la primera parte del art&amp;iacute;culo, en esta segunda entrega trataremos acerca de la forma de insertar dicha informaci&amp;oacute;n en una base de datos SQL Server.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de la base de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Finalizada la creaci&amp;oacute;n de la hoja de c&amp;aacute;lculo, volcaremos su contenido en una base de datos SQL Server, que crearemos a continuaci&amp;oacute;n ejecutando el siguiente script desde SQL Server Management Studio.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Como acabamos de comprobar, adem&amp;aacute;s de la tabla que albergar&amp;aacute; los datos que generamos desde Excel, tambi&amp;eacute;n crearemos las tablas cat&amp;aacute;logo, que contendr&amp;aacute;n las descripciones de ciertos campos de c&amp;oacute;digo existentes en la tabla DatosPoblacion, con las que estableceremos las oportunas relaciones.&amp;nbsp;&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;b&gt;Importar los datos de Excel desde SQL Server&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para insertar datos en la tabla DatosPoblacion de SQL Server, utilizaremos la funci&amp;oacute;n OPENROWSET de Transact-SQL de la siguiente manera.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Sin embargo, es posible que al intentar ejecutar esta sentencia de inserci&amp;oacute;n, nos encontremos con un error, que nos informa de que SQL Server no est&amp;aacute; configurado para realizar consultas de estas caracter&amp;iacute;sticas, denominadas &amp;#39;Ad Hoc Distributed Queries&amp;#39;.&lt;/p&gt;
&lt;p&gt;Si queremos comprobar la configuraci&amp;oacute;n de opciones de SQL Server, debemos ejecutar el procedimiento almacenado de sistema sp_configure. No obstante, lo m&amp;aacute;s probable es que entre las opciones mostradas, no veamos la configuraci&amp;oacute;n de consultas distribuidas. Si estamos en este caso, tenemos que activar la visualizaci&amp;oacute;n de opciones avanzadas utilizando las siguientes sentencias.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Ahora ya podremos ver el valor de la opci&amp;oacute;n &amp;#39;Ad Hoc Distributed Queries&amp;#39; al ejecutar sp_configure. Para activarlo ejecutaremos lo siguiente.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Al volver al ejecutar sp_configure, veremos que ya est&amp;aacute; activada la posibilidad de ejecutar consultas distribuidas.&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma, la anterior sentencia con OPENROWSET ya funcionar&amp;aacute; correctamente, llenando la tabla DatosPoblacion con el contenido del archivo GenerarDatosPoblacion.xlsx.&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Optimizando la importaci&amp;oacute;n de datos de Excel&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En el punto actual podemos encontrarnos, no obstante, ante un problema de rendimiento, ya que si hemos seguido los pasos indicados anteriormente durante la creaci&amp;oacute;n del archivo Excel, tendremos una hoja de c&amp;aacute;lculo con un mill&amp;oacute;n de filas, que puede tardar alrededor de quince minutos en cargarse en la tabla de SQL Server. Para el ejemplo que estamos desarrollando en este art&amp;iacute;culo se ha utilizado una m&amp;aacute;quina virtual con Windows 7 como sistema operativo y 1,5 GB de memoria, por lo que los mencionados tiempos pueden variar en funci&amp;oacute;n de la configuraci&amp;oacute;n del equipo utilizado para estas pruebas.&lt;/p&gt;
&lt;p&gt;Si queremos disminuir estos tiempos de carga podemos optar por el uso de la t&amp;eacute;cnica alternativa de traspaso de datos que explicamos seguidamente.&lt;/p&gt;
&lt;p&gt;En primer lugar volveremos a abrir desde Excel el archivo GenerarDatosPoblacion.xlsx, guard&amp;aacute;ndolo como archivo de tipo &amp;quot;CSV (delimitado por comas)&amp;quot;.&amp;nbsp;&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_16.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_16.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;De esta forma obtendremos un archivo de texto con los campos delimitados por el car&amp;aacute;cter de punto y coma. Podemos ver su contenido abri&amp;eacute;ndolo con el Bloc de notas.&amp;nbsp;&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_17.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_17.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n crearemos en la base de datos una nueva tabla con la siguiente estructura.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;En esta nueva tabla importaremos el contenido del archivo GenerarDatosPoblacion.csv, utilizando la sentencia BULK INSERT de Transact-SQL. Mediante la opci&amp;oacute;n FIELDTERMINATOR especificaremos el car&amp;aacute;cter usado como separador de campos, mientras que con la opci&amp;oacute;n FIRSTROW indicaremos que la lectura de datos comience en la segunda fila del archivo, ya que la primera contiene los nombres de las columnas.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;El tiempo consumido por esta operaci&amp;oacute;n de inserci&amp;oacute;n masiva en la tabla DatosPoblacionExcel ser&amp;aacute; de unos treinta segundos.&lt;/p&gt;
&lt;p&gt;Para terminar con este proceso, insertaremos en la tabla DatosPoblacion los registros de la tabla DatosPoblacionExcel, excluyendo los campos innecesarios, como vemos en la siguiente sentencia, cuya ejecuci&amp;oacute;n tardar&amp;aacute; unos 15 segundos aproximadamente.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Como acabamos de comprobar, esta t&amp;eacute;cnica de inserci&amp;oacute;n de datos, si bien nos obliga a realizar un paso adicional, supone una importante ganancia de tiempo, ya que emplea menos de un minuto en el traspaso de datos a la tabla DatosPoblacion, frente a los quince minutos utilizados por la funci&amp;oacute;n OPENROWSET.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Importando el resto de tablas cat&amp;aacute;logo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para las tablas CCAA y Pais, recurriremos a dos archivos Excel que contienen, respectivamente, la clasificaci&amp;oacute;n oficial de &lt;a href="http://www.madrid.org/iestadis/fijas/clasificaciones/descarga/ccaaprov.zip"&gt;comunidades aut&amp;oacute;nomas&lt;/a&gt; y &lt;a href="http://www.madrid.org/iestadis/fijas/clasificaciones/descarga/cozonu.zip"&gt;pa&amp;iacute;ses&lt;/a&gt;. Estos archivos se encuentran disponibles en formato comprimido, en el sitio Web del &lt;a href="http://www.madrid.org/iestadis/index.html"&gt;Instituto de Estad&amp;iacute;stica de la Comunidad de Madrid&lt;/a&gt;. Una vez descargados y descomprimidos ejecutaremos las siguientes sentencias SQL para importarlos a nuestra base de datos.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Observemos que seg&amp;uacute;n la versi&amp;oacute;n de Excel del archivo a importar, en la funci&amp;oacute;n OPENROWSET&amp;nbsp; utilizaremos un proveedor distinto para obtener los datos. Si el archivo corresponde a Excel 2007-2010 emplearemos &amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;, mientras que para versiones anteriores ser&amp;aacute; &amp;#39;Microsoft.Jet.OLEDB.4.0&amp;#39;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ajustando el c&amp;oacute;digo de pa&amp;iacute;s en la tabla DatosPoblacion&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si observamos con detenimiento los registros de la tabla Pais, nos percataremos de que los valores del campo Pais_ID no son correlativos; siendo, adem&amp;aacute;s, el valor menor 4 y el mayor 894.&amp;nbsp;&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_18.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_18.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esto contrasta con los datos existentes en el campo del mismo nombre correspondiente a la tabla DatosPoblacion, ya que, si bien el valor m&amp;aacute;ximo y m&amp;iacute;nimo de dicho campo tambi&amp;eacute;n est&amp;aacute; entre 4 y 894, encontraremos una buena cantidad de registros en los que el campo Pais_ID no corresponder&amp;aacute; a ning&amp;uacute;n valor en la tabla Pais.&lt;/p&gt;
&lt;p&gt;Para solucionar este problema vamos a recurrir a un par de t&amp;eacute;cnicas, de las cuales, la primera consistir&amp;aacute; en tomar, de la tabla DatosPoblacion, cada uno de los valores del campo Pais_ID que no existan en la tabla Pais, sum&amp;aacute;ndole uno hasta que lleguemos a un valor que s&amp;iacute; exista en la mencionada tabla cat&amp;aacute;logo de pa&amp;iacute;ses. Este proceso lo implementaremos en la funci&amp;oacute;n de SQL Server que vemos a continuaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La actualizaci&amp;oacute;n del campo Pais_ID en la tabla DatosPoblacion la llevaremos a cabo con la siguiente sentencia.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La segunda de las t&amp;eacute;cnicas resulta m&amp;aacute;s directa, ya que evitamos el uso de la funci&amp;oacute;n de b&amp;uacute;squeda del campo Pais_ID en la tabla de pa&amp;iacute;ses. Lo que hacemos en este caso es una actualizaci&amp;oacute;n del campo Pais_ID para toda la tabla DatosPoblacion, buscando en la tabla Pais, el valor de Pais_ID m&amp;aacute;s pr&amp;oacute;ximo al que existe en el mismo campo de la tabla DatosPoblacion.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;En ambos casos, conseguimos que todos los registros de la tabla DatosPoblacion crucen correctamente con la tabla Pais por el campo Pais_ID.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Inserci&amp;oacute;n manual de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s de las operaciones anteriores, la &amp;uacute;nica tabla que permanece sin datos es Sexo, por lo que ejecutaremos las siguientes sentencias, que crear&amp;aacute;n los registros necesarios.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Estableciendo relaciones entre las tablas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para finalizar la creaci&amp;oacute;n de la base de datos, estableceremos las oportunas relaciones entre los campos de la tabla DatosPoblacion y el resto de tablas cat&amp;aacute;logo, utilizando las siguientes sentencias.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Despu&amp;eacute;s de esta operaci&amp;oacute;n damos por concluido este art&amp;iacute;culo, en el que hemos explicado las diferentes partes de un proceso para generar, desde Excel, un volumen considerable de datos de prueba, que poder utilizar posteriormente desde SQL Server. En el siguiente &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201104/GenerarDatosPruebaExcelEjemplosZip.txt"&gt;enlace&lt;/a&gt; se encuentra disponible el c&amp;oacute;digo del ejemplo.&amp;nbsp;Esperamos 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=193179" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /></entry><entry><title>Programación en Silverlight 4.0, de Marino Posadas</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/04/27/programaci-243-n-en-silverlight-4-0-de-marino-posadas.aspx" /><id>/blogs/lmblanco/archive/2011/04/27/programaci-243-n-en-silverlight-4-0-de-marino-posadas.aspx</id><published>2011-04-27T18:59:00Z</published><updated>2011-04-27T18:59:00Z</updated><content type="html">&lt;p&gt;Marino Posadas acaba de publicar un libro sobre Silverlight 4.0, en el que como es su costumbre, adem&amp;aacute;s de realizar una introducci&amp;oacute;n a esta tecnolog&amp;iacute;a, aborda con profundidad y profusi&amp;oacute;n todos aquellos aspectos necesarios para capacitarnos en la construcci&amp;oacute;n de aplicaciones para esta versi&amp;oacute;n de Silverlight.&lt;/p&gt;
&lt;p&gt;Tras la parte inicial dedicada a la arquitectura de Silverlight y las aplicaciones RIA, as&amp;iacute; como el obligado cap&amp;iacute;tulo sobre XAML, el texto nos ofrece una serie de detallados cap&amp;iacute;tulos sobre las caracter&amp;iacute;sticas visuales, layout, aplicaci&amp;oacute;n de transformaciones, 3D, interacci&amp;oacute;n con el modelo HTML-DOM y un abordaje de Expression Blend 4 desde la perspectiva del desarrollador. Finalmente, como colof&amp;oacute;n, encontramos un cap&amp;iacute;tulo dedicado a Windows Phone 7, esencial para todo aquel que quiera iniciarse en el desarrollo de aplicaciones para los dispositivos m&amp;oacute;viles que funcionan bajo esta plataforma.&lt;/p&gt;
&lt;p&gt;En resumen, un excelente libro de un no menos excelente autor, que ya est&amp;aacute; disponible en &lt;a href="http://www.dotnetmania.com/libros/"&gt;dotNetMan&amp;iacute;a&lt;/a&gt;.&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=193094" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>Generar datos de prueba para SQL Server desde Excel. Operaciones en Excel (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/04/26/generar-datos-de-prueba-para-sql-server-desde-excel-operaciones-desde-excel-1.aspx" /><id>/blogs/lmblanco/archive/2011/04/26/generar-datos-de-prueba-para-sql-server-desde-excel-operaciones-desde-excel-1.aspx</id><published>2011-04-26T17:20:00Z</published><updated>2011-04-26T17:20:00Z</updated><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La creaci&amp;oacute;n de datos de muestreo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Durante las diversas fases del desarrollo de una aplicaci&amp;oacute;n, en la mayor parte de las ocasiones, nos encontramos ante la necesidad de tener a nuestra disposici&amp;oacute;n un conjunto de datos de prueba, para poder utilizarlos en los diferentes procesos que estamos desarrollando. Una situaci&amp;oacute;n similar se produce si estamos construyendo un sistema de informaci&amp;oacute;n basado en cubos de datos OLAP mediante SQL Server Analysis Services, ya que, por lo general, en estos casos necesitaremos adem&amp;aacute;s, que el volumen de los datos sea de un tama&amp;ntilde;o considerable, para poder realizar simulaciones de an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;Supongamos que tenemos que generar una base de datos con informaci&amp;oacute;n poblacional, en la que una tabla albergar&amp;iacute;a los datos de los individuos tales como edad, c&amp;oacute;digos de comunidad aut&amp;oacute;noma de residencia, pa&amp;iacute;s de procedencia, sexo, fecha de alta en el registro, etc. Por otro lado, necesitar&amp;iacute;amos tambi&amp;eacute;n una serie de tablas cat&amp;aacute;logo de pa&amp;iacute;ses, comunidades aut&amp;oacute;nomas, y dem&amp;aacute;s valores relacionados con los campos de la tabla de individuos.&lt;/p&gt;
&lt;p&gt;Entre todo el abanico de utilidades, trucos, etc., que existen para llevar a cabo esta tarea, en el presente art&amp;iacute;culo haremos uso de Excel como herramienta para la generaci&amp;oacute;n del conjunto de datos ficticios correspondiente a los individuos, que posteriormente volcaremos en una base de datos SQL Server, la cual podr&amp;iacute;amos usar como fuente de datos de la aplicaci&amp;oacute;n o sistema en desarrollo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creando los datos con Excel&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Una vez iniciado Excel 2010 (tambi&amp;eacute;n podemos utilizar versiones anteriores), nuestra primera tarea ser&amp;aacute; la creaci&amp;oacute;n de una columna con los valores que nos servir&amp;aacute;n para identificar las filas de la tabla. La forma m&amp;aacute;s simple de generarlos, consiste en introducir un par de n&amp;uacute;meros correlativos en sendas celdas de una de las columnas de la hoja de c&amp;aacute;lculo, seleccionar ambas celdas, y arrastrar el marcador de relleno hasta la &amp;uacute;ltima fila para la cual queramos generar los n&amp;uacute;meros.&amp;nbsp;&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_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No obstante, la generaci&amp;oacute;n de valores mediante esta t&amp;eacute;cnica puede resultar un tanto engorrosa en el caso de que debamos producir una gran cantidad de filas y/o columnas, por lo que para la creaci&amp;oacute;n de datos en todas las columnas de la hoja vamos a recurrir a un medio m&amp;aacute;s flexible a la par que potente: las macros de Excel.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de una macro&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para crear una macro haremos clic en la pesta&amp;ntilde;a Vista de la cinta de opciones de Excel, y dentro del grupo Macros haremos clic en la opci&amp;oacute;n del mismo nombre, que abrir&amp;aacute; el cuadro de di&amp;aacute;logo Macro, donde escribiremos el nombre de nuestra macro: CrearDatosPoblacion.&amp;nbsp;&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_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Haciendo clic en el bot&amp;oacute;n Crear, se abrir&amp;aacute; la ventana de Visual Basic para Aplicaciones (VBA), con el editor de la nueva macro reci&amp;eacute;n creada, para que podamos empezar a escribir su c&amp;oacute;digo.&amp;nbsp;&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_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dentro del cuerpo del procedimiento CrearDatosPoblaci&amp;oacute;n, escribiremos el siguiente bloque de c&amp;oacute;digo, donde en primer lugar, limpiaremos las celdas de la hoja de c&amp;aacute;lculo en la que estemos actualmente posicionados. A continuaci&amp;oacute;n solicitaremos al usuario que introduzca, mediante una caja de di&amp;aacute;logo InputBox, el n&amp;uacute;mero de filas a generar. Despu&amp;eacute;s de insertar el t&amp;iacute;tulo de la columna, introduciremos los dos primeros valores que inician la serie, la cual generaremos mediante el m&amp;eacute;todo Selection.AutoFill.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&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;limpiar las celdas de la hoja de c&amp;aacute;lculo&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;N&amp;uacute;mero de registros a generar&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;columna fila_id&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;t&amp;iacute;tulo de columna&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;valores iniciales de la serie a generar&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;seleccionar rango de valores iniciales&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;rellenar rango total de celdas&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;br /&gt;&lt;/pre&gt;
&lt;br /&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.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para ejecutar la macro seleccionaremos la opci&amp;oacute;n de men&amp;uacute; Ejecutar | Ejecutar Sub/UserForm, o pulsaremos la tecla F5, rellen&amp;aacute;ndose la primera columna de la hoja con la cantidad de valores indicada en el InputBox.&amp;nbsp;&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_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Antes de proseguir grabaremos nuestro trabajo desde la ventana de VBA o de Excel, teniendo en cuenta que deberemos hacerlo en un archivo de tipo &amp;quot;Libro de Excel habilitado para macros&amp;quot; (extensi&amp;oacute;n .xlsm), de lo que seremos avisados por un cuadro de di&amp;aacute;logo en el momento de la grabaci&amp;oacute;n. Haciendo clic en el bot&amp;oacute;n No de dicho di&amp;aacute;logo, guardaremos nuestra hoja de c&amp;aacute;lculo en un archivo con el nombre GenerarDatosPoblacion.xlsm.&amp;nbsp;&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_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Generaci&amp;oacute;n de datos aleatorios&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La siguiente columna a crear corresponder&amp;aacute; a la edad de las personas; en ella, necesitaremos generar valores aleatorios entre un intervalo de n&amp;uacute;meros, que representen las edades m&amp;aacute;xima y m&amp;iacute;nima que una persona puede tener, por ejemplo, entre 0 y 120.&lt;/p&gt;
&lt;p&gt;Para crear, en una celda de Excel, un valor aleatorio comprendido entre dos n&amp;uacute;meros, podemos utilizar una f&amp;oacute;rmula que incluya la funci&amp;oacute;n ALEATORIO.ENTRE, que recibe como par&amp;aacute;metro los mencionados n&amp;uacute;meros, devolviendo como resultado el n&amp;uacute;mero generado.&amp;nbsp;&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_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Trasladando esta funcionalidad a la macro que estamos desarrollando, a&amp;ntilde;adiremos a la misma el siguiente bloque de c&amp;oacute;digo, en el que asignaremos a una celda de la segunda columna una expresi&amp;oacute;n de f&amp;oacute;rmula conteniendo RANDBETWEEN(0,120) (equivalente a la funci&amp;oacute;n ALEATORIO.ENTRE), seleccionaremos dicha celda, y repetiremos la f&amp;oacute;rmula que contiene a lo largo del rango de celdas, usando el m&amp;eacute;todo ActiveCell.AutoFill.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;edad&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Ejecutando otra vez la macro, obtendremos la nueva columna con los datos de edad.&amp;nbsp;&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_08.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_08.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En nuestro siguiente paso le toca el turno a la columna con los valores para el sexo de los individuos. Aqu&amp;iacute; podr&amp;iacute;amos haber usado dos n&amp;uacute;meros: 1 y 2, generados igualmente de forma aleatoria, para identificar respectivamente a hombre y mujer, pero vamos a complicar un poco esta operaci&amp;oacute;n, utilizando en su lugar las letras H y M como valores para la columna, por lo que el problema se encuentra ahora en c&amp;oacute;mo generar aleatoriamente estas letras en las celdas de la columna, ya que la funci&amp;oacute;n RANDBETWEEN s&amp;oacute;lo recibe y devuelve resultados num&amp;eacute;ricos.&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n es muy simple, ya que tambi&amp;eacute;n consiste en utilizar la funci&amp;oacute;n RANDBETWEEN, pero combin&amp;aacute;ndola con la expresi&amp;oacute;n de decisi&amp;oacute;n IF. A RANDBETWEEN le pasaremos los n&amp;uacute;meros 1 y 2 como par&amp;aacute;metros, y seg&amp;uacute;n el resultado obtenido, mediante IF devolveremos la letra H o M. A continuaci&amp;oacute;n se muestra el bloque de c&amp;oacute;digo para esta columna, que a&amp;ntilde;adiremos a la macro.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;sexo&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;br /&gt;&lt;/pre&gt;
&lt;br /&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.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para las dos siguientes columnas: c&amp;oacute;digo de comunidad aut&amp;oacute;noma de residencia y c&amp;oacute;digo de pa&amp;iacute;s de procedencia, seguiremos la misma mec&amp;aacute;nica que en la columna de edades, si bien utilizando distintos intervalos num&amp;eacute;ricos.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;ccaa&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;pa&amp;iacute;s&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;br /&gt;&lt;/pre&gt;
&lt;br /&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.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_10.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_10.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Nuestro siguiente paso consistir&amp;aacute; en crear los datos de una supuesta fecha de alta de los individuos en este sistema poblacional, tarea que realizaremos en dos fases. En primer lugar, crearemos cada parte de la fecha en columnas separadas.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;elementos de fecha:&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;a&amp;ntilde;o&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;mes&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;d&amp;iacute;a&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Como acabamos de ver, el d&amp;iacute;a es la parte de la fecha que requiere mayor trabajo, ya que debemos poner cuidado en evitar la generaci&amp;oacute;n, por ejemplo, de un d&amp;iacute;a 31 si en la columna de mes tenemos el valor 2. Esto lo solucionaremos comprobando, en primer lugar, el valor de dicha columna de mes, y en funci&amp;oacute;n del mismo, usaremos un intervalo distinto para generar el d&amp;iacute;a; para ello, en la f&amp;oacute;rmula utilizaremos varias expresiones IF combinadas con funciones RANDBETWEEN.&amp;nbsp;&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_11.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_11.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En la segunda fase de esta operaci&amp;oacute;n, crearemos una &amp;uacute;ltima columna en la hoja de c&amp;aacute;lculo con una fecha en un formato comprensible para SQL Server, fruto de la concatenaci&amp;oacute;n de las anteriores columnas de anualidad, mes y d&amp;iacute;a.&lt;/p&gt;
&lt;p&gt;Es necesario tener en cuenta, al componer la fecha de esta manera, que debemos a&amp;ntilde;adir un cero al mes y al d&amp;iacute;a, cuando estos valores tengan solamente un d&amp;iacute;gito.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" 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;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;componer fecha&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;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Al volver a ejecutar la macro, obtendremos la fecha correctamente formateada en la &amp;uacute;ltima columna. En esta ocasi&amp;oacute;n, adem&amp;aacute;s, estableceremos la cifra de registros a generar en un mill&amp;oacute;n, de esa forma probaremos el potencial de creaci&amp;oacute;n de los datos.&amp;nbsp;&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_12.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_12.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para finalizar las operaciones con Excel grabaremos el archivo, esta vez con formato de &amp;quot;Libro de Excel&amp;quot; (extensi&amp;oacute;n .xlsx). Nuevamente aparecer&amp;aacute; el cuadro de di&amp;aacute;logo de aviso, que nos informar&amp;aacute; de que no podemos guardar las macros en un archivo .xlsx, al que contestaremos haciendo clic en S&amp;iacute;.&lt;/p&gt;
&lt;p&gt;Llegados a este punto concluimos la primera parte del art&amp;iacute;culo; en la segunda entrega explicaremos c&amp;oacute;mo traspasar los datos que acabamos de crear a SQL Server.&lt;/p&gt;
&lt;p&gt;Un saludo.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=193001" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /></entry><entry><title>Acceso a datos en Silverlight mediante DomainDataSource</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/03/29/acceso-a-datos-en-silverlight-mediante-domaindatasource.aspx" /><id>/blogs/lmblanco/archive/2011/03/29/acceso-a-datos-en-silverlight-mediante-domaindatasource.aspx</id><published>2011-03-29T18:00:00Z</published><updated>2011-03-29T18:00:00Z</updated><content type="html">&lt;p&gt;En el pasado n&amp;uacute;mero 78 de &lt;a href="http://www.dotnetmania.com/"&gt;dotNetMan&amp;iacute;a&lt;/a&gt; publiqu&amp;eacute; un art&amp;iacute;culo titulado &amp;quot;DomainDataSource. Un gestor de datos en Silverlight para la interfaz de usuario&amp;quot;, sobre el uso del componente DomainDataSource en la realizaci&amp;oacute;n de las operaciones de manejo de datos en una aplicaci&amp;oacute;n Silverlight. Se trata de un art&amp;iacute;culo que tambi&amp;eacute;n se encuentra disponible en los siguientes sitios web: &lt;a href="http://www.programacion.com/articulo/domaindatasource-_un_gestor_de_datos_en_silverlight_para_la_interfaz_de_usuario_712"&gt;enlace1&lt;/a&gt; y &lt;a href="http://www.desarrolloweb.com/articulos/domaindatasource-dotnet.html"&gt;enlace2&lt;/a&gt;. Espero que os resulte de utilidad.&amp;nbsp;&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=191265" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>La licencia de .NET Reflector pasa a ser de pago</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/02/02/la-licencia-de-net-reflector-pasa-a-ser-de-pago.aspx" /><id>/blogs/lmblanco/archive/2011/02/02/la-licencia-de-net-reflector-pasa-a-ser-de-pago.aspx</id><published>2011-02-02T18:17:00Z</published><updated>2011-02-02T18:17:00Z</updated><content type="html">&lt;p&gt;Despu&amp;eacute;s de la&amp;nbsp;adquisici&amp;oacute;n de &lt;a href="http://www.red-gate.com/products/dotnet-development/reflector/"&gt;.NET Reflector&lt;/a&gt;&amp;nbsp;por parte de &lt;a href="http://www.red-gate.com/"&gt;Red Gate&lt;/a&gt; hace alrededor de dos a&amp;ntilde;os y medio, finalmente ha ocurrido algo que m&amp;aacute;s o menos creo que todos pens&amp;aacute;bamos que suceder&amp;iacute;a. Red Gate empezar&amp;aacute; a cobrar a principios de marzo por la licencia de .NET Reflector. En el siguiente &lt;a href="http://www.youtube.com/watch?v=TKnEjiSGZLA&amp;amp;feature=player_embedded"&gt;video&lt;/a&gt;, Simon Galbraith, uno de los responsables de la compa&amp;ntilde;&amp;iacute;a, explica las motivaciones que les han llevado a tomar esta medida.&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=188337" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term=".NET" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/.NET/default.aspx" /><category term="Varios" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Varios/default.aspx" /></entry><entry><title>Mejorando la experiencia de usuario en el control DataForm de Silverlight (y 3)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/01/26/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-y-3.aspx" /><id>/blogs/lmblanco/archive/2011/01/26/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-y-3.aspx</id><published>2011-01-26T17:57:00Z</published><updated>2011-01-26T17:57:00Z</updated><content type="html">&lt;p&gt;En esta tercera entrega del art&amp;iacute;culo seguiremos con nuestra tarea de editar los campos del DataForm usando dos controles sobradamente conocidos por la gran mayor&amp;iacute;a de desarrolladores: ComboBox y RadioButton. El c&amp;oacute;digo fuente del proyecto est&amp;aacute; disponible &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201101/DataFormUXZip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ComboBox. Seleccionando el valor del campo en una lista desplegable&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Continuamos con las operaciones de selecci&amp;oacute;n en listas de valores de la mano de uno de los grandes cl&amp;aacute;sicos entre los controles de usuario: ComboBox.&lt;/p&gt;
&lt;p&gt;Del mismo modo que en los anteriores controles, el control ComboBox tambi&amp;eacute;n necesita una colecci&amp;oacute;n de elementos para mostrar en su lista desplegable; pero en este caso, en lugar de tratarse de una colecci&amp;oacute;n simple de valores, emplearemos la colecci&amp;oacute;n de entidades de tipo Customer obtenidas a partir del control DomainDataSource ddsCustomers, que anteriormente a&amp;ntilde;adimos a la p&amp;aacute;gina MainPage.xaml.&lt;/p&gt;
&lt;p&gt;En primer lugar trasladaremos el control ddsCustomers al bloque de recursos de la p&amp;aacute;gina XAML, operaci&amp;oacute;n necesaria para que el ComboBox tenga acceso a los datos que ddsCustomers proporciona. Adicionalmente, ordenaremos por la propiedad CustomerName de los objetos Customer el resultado devuelto por este DomainDataSource, utilizando para ello una etiqueta SortDescriptors.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n a&amp;ntilde;adiremos un ComboBox a la plantilla EditTemplate del DataForm, dentro del DataField reservado a la informaci&amp;oacute;n del cliente de la factura. El c&amp;oacute;digo XAML que emplearemos ser&amp;aacute; el siguiente.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;ddsCustomers&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;QueryName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;GetCustomers&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;domainctx:MusicaGestDomainContext&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.SortDescriptors&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:SortDescriptor&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;PropertyPath&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;CustomerName&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.SortDescriptors&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Cliente:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Orientation&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Horizontal&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                     &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; 
                     &lt;span style="color:#ff0000;"&gt;IsEnabled&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComboBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cboCustomers&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;200&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5,0,0,0&amp;quot;&lt;/span&gt;
                      &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Source={StaticResource ddsCustomers}, Path=Data}&amp;quot;&lt;/span&gt;
                      &lt;span style="color:#ff0000;"&gt;DisplayMemberPath&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;CustomerName&amp;quot;&lt;/span&gt;
                      &lt;span style="color:#ff0000;"&gt;SelectedValuePath&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;CustomerId&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Respecto a la configuraci&amp;oacute;n de las propiedades del ComboBox, a la propiedad ItemsSource le asignaremos una expresi&amp;oacute;n de enlace a datos cuya fuente sea el DomainDataSource que hemos situado como recurso; mientras que las propiedades DisplayMemberPath y SelectedValuePath contendr&amp;aacute;n, respectivamente, los valores CustomerName y CustomerId, que corresponden a los nombres de las propiedades de los objetos Customer contenidos en la colecci&amp;oacute;n de entidades asignada al ComboBox. Con DisplayMemberPath le indicamos al ComboBox la propiedad a utilizar para los valores a mostrar en la lista, y SelectedValuePath es la propiedad que el control utilizar&amp;aacute; internamente para informar al DataForm del identificador de cliente seleccionado para la factura.&lt;/p&gt;
&lt;p&gt;En el estado actual de la aplicaci&amp;oacute;n, cada vez que hagamos clic en el bot&amp;oacute;n de edici&amp;oacute;n del DataForm, el ComboBox siempre mostrar&amp;aacute;, para CustomerName, el primer valor de la colecci&amp;oacute;n, sin mantener la adecuada correspondencia con el valor de CustomerId.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_12.JPG" border="0" style="max-height:390px;max-width:407px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Para corregir este comportamiento err&amp;oacute;neo, en primer lugar, a trav&amp;eacute;s de la propiedad x:Name, asignaremos un nombre al control TextBox que contiene el valor del campo CustomerId.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt;
         &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt;
         &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt;
         &lt;span style="color:#ff0000;"&gt;IsEnabled&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Seguidamente escribiremos en el manipulador del evento ContentLoaded del DataForm un bloque de c&amp;oacute;digo en el que obtendremos la instancia del mencionado TextBox y el contexto de dominio del control ddsCustomers. Ambos objetos nos permitir&amp;aacute;n construir una expresi&amp;oacute;n LINQ, que tendr&amp;aacute; como resultado el objeto Customer cuya propiedad CustomerId corresponde &amp;nbsp;al cliente actual de la factura. Como &amp;uacute;ltimo paso de este proceso recuperaremos la instancia del ComboBox y asignaremos a su propiedad SelectedItem el objeto Customer obtenido.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        TextBox txtCustomerId = (TextBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt;);

        MusicaGestDomainContext oDomCtxCustomers = (MusicaGestDomainContext)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ddsCustomers.DomainContext;

        Customer oCustomerActual = (from oCustomer &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDomCtxCustomers.Customers
                         &lt;span style="color:#0000ff;"&gt;where&lt;/span&gt; oCustomer.CustomerId == &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;.Parse(txtCustomerId.Text)
                         select oCustomer).Single();

        ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

        cboCustomers.SelectedItem = oCustomerActual;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;A partir de ahora, el elemento visualizado por el ComboBox s&amp;iacute; corresponder&amp;aacute; con el valor adecuado cada vez que entremos en el modo de edici&amp;oacute;n del formulario de datos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_13.JPG" border="0" style="max-height:391px;max-width:408px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;No obstante, el comportamiento del ComboBox dentro del formulario de datos sigue sin ser adecuado. Expliquemos esto con m&amp;aacute;s detalle: cuando situados en modo de edici&amp;oacute;n, el usuario modifica un campo del DataForm, &amp;eacute;ste detecta el cambio habilitando el bot&amp;oacute;n OK para poder hacer clic en &amp;eacute;l y confirmar las modificaciones. Esta situaci&amp;oacute;n no se est&amp;aacute; produciendo actualmente para el ComboBox, ya que la selecci&amp;oacute;n de un nuevo valor en dicho control no hace que se active el bot&amp;oacute;n OK.&lt;/p&gt;
&lt;p&gt;Para conseguir esta funcionalidad vamos a escribir un bloque de c&amp;oacute;digo en el manipulador del evento SelectionChanged del ComboBox. Dentro de dicho evento recuperaremos las instancias de los controles ComboBox y TextBox, asignando a este &amp;uacute;ltimo el valor seleccionado en la lista desplegable, lo que producir&amp;aacute; la activaci&amp;oacute;n del bot&amp;oacute;n OK del DataForm.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComboBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cboCustomers&amp;quot;&lt;/span&gt; 
....
          &lt;span style="color:#ff0000;"&gt;SelectionChanged&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cboCustomers_SelectionChanged&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#0000ff;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; cboCustomers_SelectionChanged(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, SelectionChangedEventArgs e)
{            
    ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (cboCustomers != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sCustomerIdComboBox = cboCustomers.SelectedValue.ToString();
        TextBox txtCustomerId = (TextBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt;);
        txtCustomerId.Text = sCustomerIdComboBox;
    }
}
&lt;/p&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_14.JPG" border="0" style="max-height:396px;max-width:406px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Empleando esta t&amp;eacute;cnica ya hemos conseguido que el control ComboBox trabaje de manera coordinada con la maquinaria del DataForm. Sin embargo, demos otra vuelta de tuerca a esta situaci&amp;oacute;n: supongamos que en la plantilla EditTemplate del formulario prescindimos del TextBox txtCustomerId, &amp;iquest;c&amp;oacute;mo conseguimos entonces que el DataForm se percate de los cambios de selecci&amp;oacute;n que hagamos en el ComboBox?&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n pasa por manipular la propiedad DataForm.CurrentItem, la cual contiene el objeto que representa a la entidad actualmente en edici&amp;oacute;n en el formulario de datos; en nuestro caso un objeto Invoice.&lt;/p&gt;
&lt;p&gt;Primeramente escribiremos el siguiente bloque de c&amp;oacute;digo en el evento DataForm.ContentLoaded, que nos permitir&amp;aacute; establecer el valor correcto en el ComboBox al entrar en el modo de edici&amp;oacute;n del formulario.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;

        MusicaGestDomainContext oDomCtxCustomers = (MusicaGestDomainContext)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ddsCustomers.DomainContext;

        Customer oCustomerActual = (from oCustomer &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDomCtxCustomers.Customers
                                    &lt;span style="color:#0000ff;"&gt;where&lt;/span&gt; oCustomer.CustomerId == oInvoiceActual.CustomerId
                                    select oCustomer).Single();

        ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

        cboCustomers.SelectedItem = oCustomerActual;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;A continuaci&amp;oacute;n procederemos de forma similar en el evento ComboBox.SelectionChanged; esta vez &amp;nbsp;para asignar el valor seleccionado en el ComboBox a la propiedad Invoice.CustomerId de la entidad actualmente en edici&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; cboCustomers_SelectionChanged(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, SelectionChangedEventArgs e)
{
    ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (cboCustomers != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; nCustomerIdComboBox = (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)cboCustomers.SelectedValue;
        Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
        oInvoiceActual.CustomerId = nCustomerIdComboBox;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Como resultado, al editar ahora la entidad en el DataForm, en el campo del cliente s&amp;oacute;lo aparecer&amp;aacute; el ComboBox.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_15.JPG" border="0" style="max-height:392px;max-width:408px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;RadioButton. Selecci&amp;oacute;n de opciones autoexcluyentes&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;RadioButton es un control que representa una alternativa m&amp;aacute;s en la manera en que podemos editar/seleccionar los valores para un campo en el DataForm, ya que mediante un conjunto de controles de este tipo, podemos ofrecer al usuario varias opciones entre las cuales elegir una para asignar como valor al campo del formulario.&lt;/p&gt;
&lt;p&gt;Vamos a emplear este control para editar el campo Region de la tabla Invoice. Dicho campo tiene cinco valores posibles en esta tabla: Asia, Europe, North America, South America y Oceania, por lo que a&amp;ntilde;adiremos el mismo n&amp;uacute;mero de controles RadioButton a nuestra p&amp;aacute;gina, dentro de la plantilla EditTemplate del DataForm, usando el siguiente bloque de c&amp;oacute;digo XAML.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Regi&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtAsia&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Asia&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtEurope&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Europe&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtNorthAmerica&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;North America&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtSouthAmerica&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;South America&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtOceania&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Oceania&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Para que el formulario considere a todos estos controles como pertenecientes a un mismo grupo, de forma que solamente uno de ellos pueda estar seleccionado a la vez, hemos asignado el mismo valor a su propiedad GroupName.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n necesitamos codificar la l&amp;oacute;gica para que el RadioButton adecuado quede marcado cuando entramos en modo de edici&amp;oacute;n de una entidad, para lo cual a&amp;ntilde;adiremos el siguiente c&amp;oacute;digo al evento ContentLoaded del formulario de datos, en el que una vez obtenida la instancia de la entidad a editar, y bas&amp;aacute;ndonos en el valor de su propiedad Region, obtendremos del formulario el RadioButton correspondiente, para marcarlo mediante su propiedad IsChecked. N&amp;oacute;tese que puesto que algunos nombres de regi&amp;oacute;n est&amp;aacute;n formados por dos palabras, para componer el nombre del RadioButton, eliminamos los espacios en blanco mediante el m&amp;eacute;todo string.Replace.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sRegion = oInvoiceActual.Region;
        RadioButton rbtRegion = (RadioButton)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;rbt&amp;quot;&lt;/span&gt; + sRegion.Replace(&lt;span style="color:#006080;"&gt;&amp;quot; &amp;quot;&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty));
        rbtRegion.IsChecked = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_16.JPG" border="0" style="max-height:455px;max-width:409px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La otra parte de la funcionalidad que debemos implementar para estos controles corresponde al cambio en la selecci&amp;oacute;n del RadioButton mientras estamos en modo de edici&amp;oacute;n, ya que debemos actualizar la propiedad Region de la entidad Invoice que estamos editando con el valor del RadioButton seleccionado. Con tal finalidad, en la declaraci&amp;oacute;n de los controles en el c&amp;oacute;digo XAML hemos incluido la llamada al m&amp;eacute;todo rbtRegion_Checked, que actuar&amp;aacute; como manejador del evento Checked. La labor de dicho m&amp;eacute;todo consiste en comprobar si el RadioButton pulsado es distinto del valor de la propiedad Region de la entidad en edici&amp;oacute;n; en caso afirmativo actualizamos el valor de la propiedad.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; rbtRegion_Checked(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
{
    Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
    RadioButton rbtRegion = (RadioButton)sender;

    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (oInvoiceActual.Region != rbtRegion.Content.ToString())
    {
        oInvoiceActual.Region = rbtRegion.Content.ToString();
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Y despu&amp;eacute;s de esta demostraci&amp;oacute;n de las capacidades de edici&amp;oacute;n del control RadioButton en el formulario de datos concluimos este art&amp;iacute;culo, en el cual hemos abordado una manera de potenciar las caracter&amp;iacute;sticas de edici&amp;oacute;n en el control DataForm, a trav&amp;eacute;s del uso de controles alternativos para los campos, en reemplazo del habitual TextBox, utilizado usualmente como control de edici&amp;oacute;n por defecto. Espero que os resulte de inter&amp;eacute;s.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=188001" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry></feed>
