<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Sparks from the Anvil</title><link>http://sqlblogcasts.com/blogs/drjohn/default.aspx</link><description>Notes on applied business intelligence by Dr. John Tunnicliffe, independent BI architect</description><dc:language>en</dc:language><generator>CommunityServer 2007.1 (Build: 20917.1142)</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/SparksFromTheAnvil" /><feedburner:info uri="sparksfromtheanvil" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>SSAS: Utility to check you have the correct data types and sizes in your cube definition</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/fnDP6x6Ufqo/ssas-utility-to-check-you-have-the-correct-data-types-and-sizes-in-your-cube-definition.aspx</link><pubDate>Thu, 15 Mar 2012 13:05:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:16145</guid><dc:creator>DrJohn</dc:creator><slash:comments>1</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=16145</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2012/03/15/ssas-utility-to-check-you-have-the-correct-data-types-and-sizes-in-your-cube-definition.aspx#comments</comments><description>&lt;p&gt;This blog describes a tool I developed which allows you to compare the data types and data sizes found in the cube’s data source view with the data types/sizes of the corresponding dimensional attribute.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;Why is this important?&amp;nbsp; Well when creating named queries in a cube’s data source view, it is often necessary to use the SQL &lt;a href="http://msdn.microsoft.com/en-us/library/ms187928.aspx" target="_blank"&gt;CAST or CONVERT&lt;/a&gt; operation to change the data type to something more appropriate for SSAS.&amp;nbsp; This is particularly important when your cube is based on an Oracle data source or using custom SQL queries rather than views in the relational database.&amp;nbsp;&amp;nbsp; The problem with BIDS is that if you change the underlying SQL query, then the size of the data type in the dimension does not update automatically.&amp;nbsp; This then causes problems during deployment whereby processing the dimension fails because the data in the relational database is wider than that allowed by the dimensional attribute. &lt;/p&gt;
&lt;p&gt;In particular, if you use some string manipulation functions provided by SQL Server or Oracle in your queries, you may find that the 10 character string you expect suddenly turns into an 8,000 character monster.&amp;nbsp; For example, the SQL Server function &lt;a href="http://msdn.microsoft.com/en-us/library/ms186862.aspx" target="_blank"&gt;REPLACE&lt;/a&gt; returns column with a width of 8,000 characters.&amp;nbsp; So if you use this function in the named query in your DSV, you will get a column width of 8,000 characters.&amp;nbsp; Although the Oracle &lt;a href="http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions134.htm" target="_blank"&gt;REPLACE &lt;/a&gt;function is far more intelligent, the generated column size could still be way bigger than the maximum length of the data actually in the field.&lt;/p&gt;
&lt;p&gt;Now this may not be a problem when prototyping, but in your production cubes you really should clean up this kind of thing as these massive strings will add to processing times and storage space. Similarly, you do not want to forget to change the size of the dimension attribute if your database columns increase in size.&lt;/p&gt;
&lt;h2&gt;Introducing CheckCubeDataTypes Utiltity&lt;/h2&gt;
&lt;p&gt;The CheckCubeDataTypes application extracts all the data types and data sizes for all attributes in the cube and compares them to the data types and data sizes in the cube’s data source view.&amp;nbsp; It then generates an Excel CSV file which contains all this metadata along with a flag indicating if there is a mismatch between the DSV and the dimensional attribute.&amp;nbsp; Note that the app not only checks all the attribute keys but also the name and value columns for each attribute. &lt;br /&gt;Another benefit of having the metadata held in a CSV text file format is that you can place the file under source code control.&amp;nbsp; This allows you to compare the metadata of the previous cube release with your new release to highlight problems introduced by new development.&lt;/p&gt;
&lt;p&gt;You can download the C# source code from here: &lt;a href="http://sqlblogcasts.com/blogs/drjohn/Samples/CheckCubeDataTypes.zip"&gt;CheckCubeDataTypes.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A typical example of the output Excel CSV file is shown below - note that the last column shows a data size mismatch by TRUE appearing in the column&lt;/p&gt;
&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/CheckCubeDataTypes.png"&gt;&lt;img border="0" src="http://sqlblogcasts.com/blogs/drjohn/CheckCubeDataTypes.png" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=16145" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/C_2300_/default.aspx">C#</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2012/03/15/ssas-utility-to-check-you-have-the-correct-data-types-and-sizes-in-your-cube-definition.aspx</feedburner:origLink></item><item><title>SSAS: Utility to export SQL code from your cube's Data Source View (DSV)</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/9b1-RTID4uc/ssas-utility-to-export-sql-code-from-your-cube-s-data-source-view-dsv.aspx</link><pubDate>Fri, 24 Feb 2012 14:19:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:16120</guid><dc:creator>DrJohn</dc:creator><slash:comments>1</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=16120</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2012/02/24/ssas-utility-to-export-sql-code-from-your-cube-s-data-source-view-dsv.aspx#comments</comments><description>&lt;p&gt;When you are working on a cube, particularly in a multi-person team, it is sometimes necessary to review what changes that have been done to the SQL queries in the cube&amp;#39;s data source view (DSV). This can be a problem as the SQL editor in the DSV is not the best interface to review code. Now of course you can cut and paste the SQL into SSMS, but you have to do each query one-by-one. What is worse your DBA is unlikely to have BIDS installed, so you will have to manually export all the SQL yourself and send him the files. To make it easy to get hold of the SQL in a Data Source View, I developed a C# utility which connects to an OLAP database and uses Analysis Services Management Objects (AMO) to obtain and export all the SQL to a series of files. The added benefit of this approach is that these SQL files can be placed under source code control which means the DBA can easily compare one version with another.&lt;/p&gt;
&lt;h2&gt;The Trick&lt;/h2&gt;
&lt;p&gt;When I came to implement this utility, I quickly found that the AMO API does not give direct access to anything useful about the tables in the data source view. Iterating through the DSVs and tables is easy, but getting to the SQL proved to be much harder. My Google searches returned little of value, so I took a look at the idea of using the XmlDom to open the DSV’s XML and obtaining the SQL from that. This is when the breakthrough happened. Inspecting the DSV’s XML I saw the things I was interested in were called&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TableType&lt;/li&gt;
&lt;li&gt;DbTableName&lt;/li&gt;
&lt;li&gt;FriendlyName&lt;/li&gt;
&lt;li&gt;QueryDefinition&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Searching Google for FriendlyName returned this page: &lt;a href="http://msdn.microsoft.com/en-us/library/ms345093.aspx"&gt;Programming AMO Fundamental Objects&lt;/a&gt; which hinted at the fact that I could use something called ExtendedProperties to obtain these XML attributes. This simplified my code tremendously to make the implementation almost trivial. So here is my code with appropriate comments. The full solution can be downloaded from here: &lt;a href="http://sqlblogcasts.com/blogs/drjohn/ExportCubeDsvSQL.zip"&gt;ExportCubeDsvSQL.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;
&lt;p&gt;using&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; System;&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;using&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; System.Data;&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;using&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; System.IO;&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;using&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; Microsoft.AnalysisServices;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font color="#800080" size="2" face="Consolas"&gt;... class code removed for clarity&lt;/font&gt;&lt;/p&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// connect to the OLAP server &lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Server&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; olapServer = &lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;new&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; &lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Server&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;();&lt;br /&gt;olapServer.Connect(config.olapServerName);&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;if&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; (olapServer != &lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;null&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;)&lt;br /&gt;{&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; 
&lt;blockquote&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// connected to server ok, so obtain reference to the OLAP database&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Database&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; olapDatabase = olapServer.Databases.FindByName(config.olapDatabaseName);&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;if&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; (olapDatabase != &lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;null&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;)&lt;br /&gt;{&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Console&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.WriteLine(&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;string&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.Format(&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;Succesfully connected to &amp;#39;{0}&amp;#39; on &amp;#39;{1}&amp;#39;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;, &lt;br /&gt;&amp;nbsp; config.olapDatabaseName, &lt;br /&gt;&amp;nbsp; config.olapServerName));&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// export SQL from each data source view (usually only one, but can be many!)&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;foreach&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; (&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;DataSourceView&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; dsv &lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;in&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; olapDatabase.DataSourceViews)&lt;br /&gt;{&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; 
&lt;blockquote&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Console&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.WriteLine(&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;string&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.Format(&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;Exporting SQL from DSV &amp;#39;{0}&amp;#39;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;, dsv.Name));&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// for each table in the DSV, export the SQL in a file&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;foreach&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; (&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;DataTable&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; dt &lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;in&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; dsv.Schema.Tables)&lt;br /&gt;{&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;/blockquote&gt;
&lt;blockquote style="MARGIN-RIGHT:0px;" dir="ltr"&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Console&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.WriteLine(&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;string&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.Format(&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;Exporting SQL from table &amp;#39;{0}&amp;#39;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;, dt.TableName));&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// get name of the table in the DSV&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// use the FriendlyName as the user inputs this and therefore has control of it&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;string&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; queryName = dt.ExtendedProperties[&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;FriendlyName&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;].ToString().Replace(&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot; &amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;, &lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;_&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;);&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;string&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; sqlFilePath = &lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Path&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.Combine(targetDir.FullName, queryName + &lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;.sql&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// delete the sql file if it exists&lt;br /&gt;&lt;font color="#800080"&gt;... file deletion&amp;nbsp;code removed for clarity&lt;/font&gt;&lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;&lt;font color="#008000" size="2" face="Consolas"&gt;// write out the SQL to a file&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;if&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; (dt.ExtendedProperties[&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;TableType&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;].ToString() == &lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;View&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;)&lt;br /&gt;{&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; 
&lt;blockquote&gt;
&lt;p&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;File&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.WriteAllText(sqlFilePath, dt.ExtendedProperties[&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;QueryDefinition&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;].ToString());&lt;/p&gt;&lt;/blockquote&gt;}&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;if&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; (dt.ExtendedProperties[&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;TableType&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;].ToString() == &lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;Table&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;)&lt;br /&gt;{&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt; 
&lt;blockquote&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;File&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.WriteAllText(sqlFilePath, dt.ExtendedProperties[&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;DbTableName&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;].ToString());&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;/blockquote&gt;
&lt;p&gt;}&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;
&lt;blockquote style="MARGIN-RIGHT:0px;" dir="ltr"&gt;
&lt;blockquote style="MARGIN-RIGHT:0px;" dir="ltr"&gt;
&lt;p&gt;}&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;
&lt;blockquote style="MARGIN-RIGHT:0px;" dir="ltr"&gt;
&lt;blockquote&gt;
&lt;p&gt;}&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;&lt;font color="#2b91af" size="2" face="Consolas"&gt;Console&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.WriteLine(&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;&lt;font color="#0000ff" size="2" face="Consolas"&gt;string&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;.Format(&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&lt;font color="#a31515" size="2" face="Consolas"&gt;&amp;quot;Successfully written out SQL scripts to &amp;#39;{0}&amp;#39;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;, targetDir.FullName));&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Consolas"&gt;&lt;font size="2" face="Consolas"&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;}&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;}&lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Of course, if you are following industry best practice, you should be basing your cube on a series of views. This will mean that this utility will be of limited practical value unless of course you are inheriting a project and want to check if someone did the implementation correctly.&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=16120" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/C_2300_/default.aspx">C#</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2012/02/24/ssas-utility-to-export-sql-code-from-your-cube-s-data-source-view-dsv.aspx</feedburner:origLink></item><item><title>Building a Dynamic OLAP Environment at #SQLbits8</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/jyK8sdsAqD4/building-a-dynamic-olap-environment-at-sqlbits8.aspx</link><pubDate>Mon, 11 Apr 2011 15:42:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:15558</guid><dc:creator>DrJohn</dc:creator><slash:comments>0</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=15558</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2011/04/11/building-a-dynamic-olap-environment-at-sqlbits8.aspx#comments</comments><description>&lt;p&gt;On Saturday I attended the &lt;a href="http://www.sqlbits.com/"&gt;SQLBits&lt;/a&gt; conference in sunny Brighton.  Great conference, well organized with lots of great speakers presenting high quality content.  
&lt;/p&gt;&lt;p&gt;For me the highlight was meeting many of the senior guys from the Redmond SQL Server product team including &lt;a href="http://www.sqlbits.com/Speakers/Richard_Tkachuk"&gt;Richard Tkachuk&lt;/a&gt;, &lt;a href="http://www.linkedin.com/pub/mark-souza/0/45/116"&gt;Mark Souza&lt;/a&gt; and &lt;a href="http://www.linkedin.com/pub/ross-mistry/1/b8b/502"&gt;Ross Mistry&lt;/a&gt;. 
&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.sqlbits.com/Speakers/Marco_Russo"&gt;Marco Russo&lt;/a&gt; presented a great session called &lt;a href="http://www.sqlbits.com/Speakers/Marco_Russo"&gt;Analysis Services Advanced Best Practice&lt;/a&gt;.  Ok so I have read his book and implement most of the best practices already, but it was great to hear it all from the author himself! 
&lt;/p&gt;&lt;p&gt;I received very positive feedback on my own session &lt;a href="http://www.sqlbits.com/Sessions/Event8/Building_a_dynamic_OLAP_environment"&gt;Building a Dynamic OLAP Environment&lt;/a&gt; which I had discussed in a &lt;a href="http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/06/building-dynamic-olap-data-marts-on-the-fly.aspx"&gt;previous post&lt;/a&gt;.   Sometime soon, the slide deck will be made available on the &lt;a href="http://www.sqlbits.com/"&gt;SQLBits&lt;/a&gt; web site along with the video of my presentation.  However, if you are eager to get your hands on it now, it can be downloaded from here: &lt;a href="http://sqlblogcasts.com/blogs/drjohn/SQLBits/BuildingDynamicOLAP.zip"&gt;BuildingDynamicOLAP.zip&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;All in all, a great conference!  I am looking forward to the next already.&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=15558" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQLBits/default.aspx">SQLBits</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2011/04/11/building-a-dynamic-olap-environment-at-sqlbits8.aspx</feedburner:origLink></item><item><title>The most dangerous SQL Script in the world!</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/r4osvp8CIPo/the-most-dangerous-sql-script-in-the-world.aspx</link><pubDate>Tue, 15 Feb 2011 10:05:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:15388</guid><dc:creator>DrJohn</dc:creator><slash:comments>0</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=15388</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/15/the-most-dangerous-sql-script-in-the-world.aspx#comments</comments><description>&lt;p&gt;In my last blog entry, I outlined how to &lt;a href="http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/13/ssis-building-sql-databases-on-the-fly-using-concatenated-sql-scripts.aspx"&gt;automate SQL Server database builds from concatenated SQL Scripts&lt;/a&gt;.  However, I did not mention how I ensure the database is clean before I rebuild it.  Clearly a simple DROP/CREATE DATABASE command would suffice; but you may not have permission to execute such commands, especially in a corporate environment controlled by a centralised DBA team.  However, you should at least have database owner permissions on the development database so you can actually do your job!  Then you can employ my universal &amp;quot;drop all&amp;quot; script which will clear down your database before you run your SQL Scripts to rebuild all the database objects.
&lt;/p&gt;&lt;h2&gt;Why start with a clean database? 
&lt;/h2&gt;&lt;p&gt;During the development process, it is all too easy to leave old objects hanging around in the database which can have unforeseen consequences.  For example, when you rename a table you may forget to delete the old table and change all the related views to use the new table.   Clearly this will mean an end-user querying the views will get the wrong data and your reputation will take a nose dive as a result!
&lt;/p&gt;&lt;p&gt;Starting with a clean, empty database and then building all your database objects using SQL Scripts using the technique outlined in my &lt;a href="http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/13/ssis-building-sql-databases-on-the-fly-using-concatenated-sql-scripts.aspx"&gt;previous blog&lt;/a&gt; means you know exactly what you have in your database.  The database can then be repopulated using SSIS and bingo; you have a data mart &amp;quot;to go&amp;quot;.
&lt;/p&gt;&lt;h2&gt;My universal &amp;quot;drop all&amp;quot; SQL Script
&lt;/h2&gt;&lt;p&gt;To ensure you start with a clean database run my universal &amp;quot;drop all&amp;quot; script which you can download from here:&amp;nbsp;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/SQL/100_drop_all.zip"&gt;100_drop_all.zip&lt;/a&gt;  
&lt;/p&gt;&lt;p&gt;By using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms189082.aspx"&gt;database catalog views&lt;/a&gt;, the script finds and drops all of the following database objects:
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Foreign key relationships
&lt;/li&gt;&lt;li&gt;Stored procedures
&lt;/li&gt;&lt;li&gt;Triggers
&lt;/li&gt;&lt;li&gt;Database triggers
&lt;/li&gt;&lt;li&gt;Views
&lt;/li&gt;&lt;li&gt;Tables
&lt;/li&gt;&lt;li&gt;Functions
&lt;/li&gt;&lt;li&gt;Partition schemes 
&lt;/li&gt;&lt;li&gt;Partition functions
&lt;/li&gt;&lt;li&gt;XML Schema Collections
&lt;/li&gt;&lt;li&gt;Schemas
&lt;/li&gt;&lt;li&gt;Types
&lt;/li&gt;&lt;li&gt;Service broker services
&lt;/li&gt;&lt;li&gt;Service broker queues
&lt;/li&gt;&lt;li&gt;Service broker contracts
&lt;/li&gt;&lt;li&gt;Service broker message types
&lt;/li&gt;&lt;li&gt;SQLCLR assemblies
&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There are two optional sections to the script: drop users and drop roles.  You may use these at your peril, particularly as you may well remove your own permissions! 
&lt;/p&gt;&lt;p&gt;Note that the script has a verbose mode which displays the SQL commands it is executing.  This can be switched on by setting @debug=1.
&lt;/p&gt;&lt;p&gt;Running this script against one of the system databases is certainly not recommended!  So I advise you to keep a USE database statement at the top of the file.
&lt;/p&gt;&lt;p&gt;Good luck and be careful!!
&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=15388" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/T-SQL/default.aspx">T-SQL</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/15/the-most-dangerous-sql-script-in-the-world.aspx</feedburner:origLink></item><item><title>SSIS: Building SQL databases on-the-fly using concatenated SQL scripts</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/F4vmRlyIXGk/ssis-building-sql-databases-on-the-fly-using-concatenated-sql-scripts.aspx</link><pubDate>Sun, 13 Feb 2011 09:49:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:15380</guid><dc:creator>DrJohn</dc:creator><slash:comments>2</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=15380</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/13/ssis-building-sql-databases-on-the-fly-using-concatenated-sql-scripts.aspx#comments</comments><description>&lt;p&gt;Over the years I have developed many techniques which help automate the whole SQL Server build process.  In my current process, where I need to &lt;a href="http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/06/building-dynamic-olap-data-marts-on-the-fly.aspx"&gt;build entire OLAP data marts on-the-fly&lt;/a&gt;, I make regular use of a simple but very effective mechanism to concatenate all the SQL Scripts together from my SSMS (SQL Server Management Studio) projects.  This proves invaluable because in two clicks I can redeploy an entire SQL Server database with all tables, views, stored procedures &lt;i&gt;etc.&lt;/i&gt;  Indeed, I can also use the concatenated SQL scripts with SSIS to build SQL Server databases on-the-fly.
&lt;/p&gt;&lt;p&gt;You may be surprised to learn that I often redeploy the database several times per day, or even several times per hour, during the development process.  This is because the deployment errors are logged and you can quickly see where SQL Scripts have object dependency errors.  For example, after changing a table structure you may have forgotten to change any related views.  The deployment log immediately points out all the objects which failed to build so you can fix and redeploy the database very quickly.  The alternative approach (i.e. doing changes in the database directly using the SSMS UI) would require you to check all dependent objects before making changes.  The chances are that you will miss something and wonder why your app returns the wrong data – a common problem caused by changing a table without re-creating dependent views.
&lt;/p&gt;&lt;h2&gt;Using SQL Projects in SSMS
&lt;/h2&gt;&lt;p&gt;A great many developers fail to make use of SQL Projects in SSMS (SQL Server Management Studio).  To me they are invaluable way of organizing your SQL Scripts.  The screenshot below shows a typical SSMS solution made up of several projects – one project for tables, another for views etc.  The key point is that the projects naturally fall into the right order in file system because of the project name.  The number in the folder or file name ensures that the projects the SQL scripts are concatenated together in the order that they need to be executed.  Hence the script filenames start with 100, 110 etc.  
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/Concat/SSMS_Project.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/Concat/SSMS_Project.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Concatenating SQL Scripts
&lt;/h2&gt;&lt;p&gt;To concatenate the SQL Scripts together into one file, I use notepad.exe to create a simple batch file (see example screenshot) which uses the TYPE command to write the content of the SQL Script files into a combined file.  As the SQL Scripts are in several folders, I simply use several TYPE command multiple times and append the output together.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/Concat/ConcatBatch.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/Concat/ConcatBatch.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;If you are unfamiliar with batch files, you may not know that the angled bracket (&amp;gt;) means write output of the program into a file.  Two angled brackets (&amp;gt;&amp;gt;) means append output of this program into a file.  So the command-line
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;DIR &amp;gt; filelist.txt 
&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;would write the content of the DIR command into a file called filelist.txt.  In the example shown above, the concatenated file is called SB_DDS.sql
&lt;/p&gt;&lt;p&gt;If, like me you place the concatenated file under source code control, then the source code control system will change the file&amp;#39;s attribute to &amp;quot;read-only&amp;quot; which in turn would cause the TYPE command to fail.  The ATTRIB command can be used to remove the read-only flag.
&lt;/p&gt;&lt;h2&gt;Using SQLCmd to execute the concatenated file
&lt;/h2&gt;&lt;p&gt;Now that the SQL Scripts are all in one big file, we can execute the script against a database using &lt;a href="http://msdn.microsoft.com/en-us/library/ms162773.aspx"&gt;SQLCmd&lt;/a&gt; using another batch file as shown below:&lt;/p&gt;&lt;p&gt;
&lt;a href="http://sqlblogcasts.com/blogs/drjohn/Concat/SQLCmd.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/Concat/SQLCmd.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms162773.aspx"&gt;SQLCmd&lt;/a&gt; has numerous options, but the script shown above simply executes the SS_DDS.sql file against the SB_DDS_DB database on the local machine and logs the errors to a file called SB_DDS.log.  So after executing the batch file you can simply check the error log to see if your database built without a hitch.  If you have errors, then simply fix the source files, re-create the concatenated file and re-run the SQLCmd to rebuild the database.  This two click operation allows you to quickly identify and fix errors in your entire database definition.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Using SSIS to execute the concatenated file
&lt;/h2&gt;&lt;p&gt;To execute the concatenated SQL script using SSIS, you simply drop an &lt;b&gt;Execute SQL&lt;/b&gt; task into your package and set the database connection as normal and then select &lt;b&gt;File Connection&lt;/b&gt; as the &lt;b&gt;SQLSourceType&lt;/b&gt; (as shown below). Create a file connection to your concatenated SQL script and you are ready to go. &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/Concat/SSIS_Execute_SQL.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/Concat/SSIS_Execute_SQL.png" border="0" alt="" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h2&gt;Tips and Tricks&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Add a new-line at end of every file&lt;/b&gt;&lt;br /&gt;The
 most common problem encountered with this approach is that the GO 
statement on the last line of one file is placed on the same line as the
 comment at the top of the next file by the TYPE command.  The easy fix 
to this is to ensure all your files have a new-line at the end.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Remove all USE database statements&lt;/b&gt;&lt;br /&gt;The
 SQLCmd identifies which database the script should be run against.&amp;nbsp; So 
you should remove all USE database commands from your scripts - 
otherwise you may get unintentional side effects!!&lt;/li&gt;&lt;li&gt;&lt;b&gt;Do the &lt;/b&gt;&lt;b&gt;Create Database separately&lt;/b&gt;&lt;br /&gt;If you are using SSIS to create the database as well as create the objects and populate the database, then invoke the CREATE DATABASE command against the master database using a separate package before calling the package that executes the concatenated SQL script.&amp;nbsp;&amp;nbsp; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=15380" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSIS/default.aspx">SSIS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/T-SQL/default.aspx">T-SQL</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQLBits/default.aspx">SQLBits</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/13/ssis-building-sql-databases-on-the-fly-using-concatenated-sql-scripts.aspx</feedburner:origLink></item><item><title>SSIS: Deploying OLAP cubes using C# script tasks and AMO</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/RGdp1NnGM9c/ssis-deploying-olap-cubes-using-c-script-tasks-and-amo.aspx</link><pubDate>Mon, 07 Feb 2011 18:07:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:15344</guid><dc:creator>DrJohn</dc:creator><slash:comments>1</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=15344</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/07/ssis-deploying-olap-cubes-using-c-script-tasks-and-amo.aspx#comments</comments><description>&lt;p&gt;As part of the continuing series on &lt;a href="http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/06/building-dynamic-olap-data-marts-on-the-fly.aspx"&gt;Building dynamic OLAP data marts on-the-fly&lt;/a&gt;, this blog entry will focus on how to automate the deployment of OLAP cubes using SQL Server Integration Services (SSIS) and Analysis Services Management Objects (AMO).   
&lt;/p&gt;&lt;p&gt;OLAP cube deployment is usually done using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms162758.aspx"&gt;Analysis Services Deployment Wizard&lt;/a&gt;.  However, this option was dismissed for a variety of reasons.  Firstly, invoking external processes from SSIS is fraught with problems as (a) it is not always possible to ensure SSIS waits for the external program to terminate; (b) we cannot log the outcome properly and (c) it is not always possible to control the server&amp;#39;s configuration to ensure the executable works correctly.  Another reason for rejecting the Deployment Wizard is that it requires the &lt;i&gt;&amp;#39;answers&amp;#39;&lt;/i&gt; to be written into four XML files.  These XML files record the three things we need to change: the name of the server, the name of the OLAP database and the connection string to the data mart.   Although it would be reasonably straight forward to change the content of the XML files programmatically, this adds another set of complication and level of obscurity to the overall process.
&lt;/p&gt;&lt;p&gt;When I first investigated the possibility of using C# to deploy a cube, I was surprised to find that there are no other blog entries about the topic.  I can only assume everyone else is happy with the Deployment Wizard!  
&lt;/p&gt;&lt;h2&gt;SSIS &amp;quot;forgets&amp;quot; assembly references
&lt;/h2&gt;&lt;p&gt;If you build your script task from scratch, you will have to remember how to overcome one of the major annoyances of working with SSIS script tasks: the forgetful nature of SSIS when it comes to assembly references.  Basically, you can go through the process of adding an assembly reference using the &lt;b&gt;Add Reference&lt;/b&gt; dialog, but when you close the script window, SSIS &amp;quot;forgets&amp;quot; the assembly reference so the script will not compile. After repeating the operation several times, you will find that SSIS only remembers the assembly reference when you specifically press the &lt;b&gt;Save All&lt;/b&gt; icon in the script window.  This problem is not unique to the AMO assembly and has certainly been a &amp;quot;feature&amp;quot; since SQL Server 2005, so I am not amazed it is still present in SQL Server 2008 R2!
&lt;/p&gt;&lt;h2&gt;Sample Package 
&lt;/h2&gt;&lt;p&gt;So let&amp;#39;s take a look at the sample SSIS package I have provided which can be downloaded from here: &lt;a href="http://sqlblogcasts.com/blogs/drjohn/DeployOlapCubeExample.zip" title="sample SSIS package"&gt;DeployOlapCubeExample.zip&lt;/a&gt;&amp;nbsp; Below is a screenshot after a successful run.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/SuccessfulDeployment.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/SuccessfulDeployment.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;h3&gt;Connection Managers
&lt;/h3&gt;&lt;p&gt;The package has three connection managers:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;AsDatabaseDefinitionFile&lt;/b&gt; is a file connection manager pointing to the .asdatabase file you wish to deploy.  Note that this can be found in the bin directory of you OLAP database project once you have clicked the &amp;quot;Build&amp;quot; button in Visual Studio
&lt;/li&gt;&lt;li&gt;&lt;b&gt;TargetOlapServerCS&lt;/b&gt; is an Analysis Services connection manager which identifies both the deployment server and the target database name.  
&lt;/li&gt;&lt;li&gt;&lt;b&gt;SourceDataMart&lt;/b&gt; is an OLEDB connection manager pointing to the data mart which is to act as the source of data for your cube.  This will be used to replace the connection string found in your .asdatabase file
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Once you have configured the connection managers, the sample should run and deploy your OLAP database in a few seconds.  Of course, in a production environment, these connection managers would be associated with package configurations or set at runtime.
&lt;/p&gt;&lt;p&gt;When you run the sample, you should see that the script logs its activity to the output screen (see screenshot above).  If you configure logging for the package, then these messages will also appear in your SSIS logging.
&lt;/p&gt;&lt;h3&gt;Sample Code Walkthrough
&lt;/h3&gt;&lt;p&gt;Next let&amp;#39;s walk through the code.  The first step is to parse the connection string provided by the&lt;b&gt; TargetOlapServerCS &lt;/b&gt;connection manager and obtain the name of both the target OLAP server and also the name of the OLAP database.  Note that the target database does not have to exist to be referenced in an AS connection manager, so I am using this as a convenient way to define both properties.
&lt;/p&gt;&lt;p&gt;We now connect to the server and check for the existence of the OLAP database.  If it exists, we drop the database so we can re-deploy.  
&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;svr.Connect(olapServerName);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (svr.Connected)
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;{
&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;font color="#339966"&gt;// Drop the OLAP database if it already exists&lt;/font&gt;
&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span&gt;Database&lt;/span&gt; db = svr.Databases.FindByName(olapDatabaseName);
&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (db != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;{
&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;db.Drop();
&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;}
&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:green;"&gt;// rest of script&lt;/span&gt;&lt;span&gt;
			&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Next we start building the XMLA command that will actually perform the deployment.  Basically this is a small chuck of XML which we need to wrap around the large &lt;b&gt;.asdatabase&lt;/b&gt; file generated by the Visual Studio build process.  
&lt;/p&gt;&lt;p&gt;&lt;span style="color:green;font-family:Courier New;font-size:10pt;"&gt;// Start generating the main part of the XMLA command
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span&gt;XmlDocument&lt;/span&gt; xmlaCommand = &lt;span style="color:blue;"&gt;new&lt;/span&gt;
			&lt;span&gt;XmlDocument&lt;/span&gt;();
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;xmlaCommand.LoadXml(&lt;span style="color:blue;"&gt;string&lt;/span&gt;.Format(&lt;span&gt;&amp;quot;&amp;lt;Batch Transaction=&amp;#39;false&amp;#39; xmlns=&amp;#39;http://schemas.microsoft.com/analysisservices/2003/engine&amp;#39;&amp;gt;&amp;lt;Alter AllowCreate=&amp;#39;true&amp;#39; ObjectExpansion=&amp;#39;ExpandFull&amp;#39;&amp;gt;&amp;lt;Object&amp;gt;&amp;lt;DatabaseID&amp;gt;{0}&amp;lt;/DatabaseID&amp;gt;&amp;lt;/Object&amp;gt;&amp;lt;ObjectDefinition/&amp;gt;&amp;lt;/Alter&amp;gt;&amp;lt;/Batch&amp;gt;&amp;quot;&lt;/span&gt;, olapDatabaseName));
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Next we need to merge two XML files which we can do by simply using setting the &lt;span style="font-family:Courier New;font-size:10pt;"&gt;InnerXml &lt;/span&gt;property of the &lt;span style="font-family:Courier New;font-size:10pt;"&gt;ObjectDefinition &lt;/span&gt;node as follows:
&lt;/p&gt;&lt;p&gt;&lt;span style="color:green;font-family:Courier New;font-size:10pt;"&gt;// load OLAP Database definition from .asdatabase file identified by connection manager 
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span&gt;XmlDocument&lt;/span&gt; olapCubeDef = &lt;span style="color:blue;"&gt;new&lt;/span&gt;
			&lt;span&gt;XmlDocument&lt;/span&gt;();
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;olapCubeDef.Load(Dts.Connections[&lt;span&gt;&amp;quot;AsDatabaseDefinitionFile&amp;quot;&lt;/span&gt;].ConnectionString);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:green;font-family:Courier New;font-size:10pt;"&gt;// merge the two XML files by obtain a reference to the ObjectDefinition node 
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;oaRootNode.InnerXml = olapCubeDef.InnerXml;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt; One hurdle I had to overcome was removing detritus from the &lt;b&gt;.asdabase&lt;/b&gt; file left by the Visual Studio build. Through an iterative process, I found I needed to remove several nodes as they caused the deployment to fail.  The XMLA error message read &amp;quot;Cannot set read-only node: CreatedTimestamp&amp;quot; or similar.  In comparing the XMLA generated with by the Deployment Wizard with that generated by my code, these read-only nodes were missing, so clearly I just needed to strip them out.  This was easily achieved using XPath to find the relevant XML nodes, of which I show one example below:
&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (&lt;span&gt;XmlNode&lt;/span&gt; node &lt;span style="color:blue;"&gt;in&lt;/span&gt; rootNode.SelectNodes(&lt;span&gt;&amp;quot;//ns1:CreatedTimestamp&amp;quot;&lt;/span&gt;, nsManager))
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;{
&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;node.ParentNode.RemoveChild(node);
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;}&lt;/span&gt;
	&lt;/p&gt;&lt;p&gt;Now we need to change the database name in both the ID and Name nodes using code such as:
&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span&gt;XmlNode&lt;/span&gt; databaseID = xmlaCommand.SelectSingleNode(&lt;span&gt;&amp;quot;//ns1:Database/ns1:ID&amp;quot;&lt;/span&gt;, nsManager);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (databaseID != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;   databaseID.InnerText = olapDatabaseName;&lt;/span&gt;
	&lt;/p&gt;&lt;p&gt;Finally we need to change the connection string to point at the relevant data mart.  Again this is easily achieved using XPath to search for the relevant nodes and then replace the content of the node with the new name or connection string.  
&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span&gt;XmlNode&lt;/span&gt; connectionStringNode = xmlaCommand.SelectSingleNode(&lt;span&gt;&amp;quot;//ns1:DataSources/ns1:DataSource/ns1:ConnectionString&amp;quot;&lt;/span&gt;, nsManager);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (connectionStringNode != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;{
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:40px;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;connectionStringNode.InnerText = Dts.Connections[&lt;span&gt;&amp;quot;SourceDataMart&amp;quot;&lt;/span&gt;].ConnectionString;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;}&lt;/span&gt;
	&lt;/p&gt;&lt;p&gt;Finally we need to perform the deployment using the &lt;span style="font-family:Courier New;font-size:10pt;"&gt;Execute&lt;/span&gt; XMLA command and check the returned &lt;span style="font-family:Courier New;font-size:10pt;"&gt;XmlaResultCollection&lt;/span&gt; for errors before setting the &lt;span style="font-family:Courier New;font-size:10pt;"&gt;Dts.TaskResult&lt;/span&gt;. 
&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span&gt;XmlaResultCollection&lt;/span&gt; oResults = svr.Execute(xmlaCommand.InnerXml);
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color:green;font-family:Courier New;font-size:10pt;"&gt;// check for errors during deployment
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (Microsoft.AnalysisServices.&lt;span&gt;XmlaResult&lt;/span&gt; oResult &lt;span style="color:blue;"&gt;in&lt;/span&gt; oResults)
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;{
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:40px;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (Microsoft.AnalysisServices.&lt;span&gt;XmlaMessage&lt;/span&gt; oMessage &lt;span style="color:blue;"&gt;in&lt;/span&gt; oResult.Messages)
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:40px;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;{
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:65.76pt;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; ((oMessage.GetType().Name == &lt;span&gt;&amp;quot;XmlaError&amp;quot;&lt;/span&gt;))
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:65.76pt;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;{
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:101.76pt;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;FireError(oMessage.Description);
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:101.76pt;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;HadError = &lt;span style="color:blue;"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:101.76pt;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-left:40px;"&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;}
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;If you are not familiar with XML programming, all this may all seem a bit daunting, but perceiver as the sample code is pretty short.
&lt;/p&gt;&lt;p&gt;If you would like the script to process the OLAP database, simply uncomment the lines in the vicinity of &lt;span style="font-family:Courier New;font-size:10pt;"&gt;Process &lt;/span&gt;method.  Of course, you can extend the script to perform your own custom processing and to even synchronize the database to a front-end server.  Personally, I like to keep the deployment and processing separate as the code can become overly complex for support staff.&lt;/p&gt;&lt;p&gt;If you want to know more, come see my session at the forthcoming &lt;a href="http://www.sqlbits.com"&gt;SQLBits conference&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=15344" width="1" height="1"&gt;</description><enclosure url="http://sqlblogcasts.com/blogs/drjohn/attachment/15344.ashx" length="16807" type="application/x-zip-compressed" /><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSIS/default.aspx">SSIS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQLBits/default.aspx">SQLBits</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/07/ssis-deploying-olap-cubes-using-c-script-tasks-and-amo.aspx</feedburner:origLink></item><item><title>Building dynamic OLAP data marts on-the-fly</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/Y71x6wJOLGc/building-dynamic-olap-data-marts-on-the-fly.aspx</link><pubDate>Sun, 06 Feb 2011 08:32:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:15341</guid><dc:creator>DrJohn</dc:creator><slash:comments>3</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=15341</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/06/building-dynamic-olap-data-marts-on-the-fly.aspx#comments</comments><description>&lt;p&gt;At the forthcoming &lt;a href="http://www.sqlbits.com/"&gt;SQLBits conference&lt;/a&gt;, I will be presenting a session on how to dynamically build an OLAP data mart on-the-fly.  This blog entry is intended to clarify exactly what I mean by an OLAP data mart, why you may need to build them on-the-fly and finally outline the steps needed to build them dynamically.  In subsequent blog entries, I will present exactly how to implement some of the techniques involved.
&lt;/p&gt;&lt;h2&gt;What is an OLAP data mart?
&lt;/h2&gt;&lt;p&gt;In data warehousing parlance, a &lt;a href="http://en.wikipedia.org/wiki/Data_mart"&gt;data mart&lt;/a&gt; is a subset of the overall corporate data provided to business users to meet specific business needs.  Of course, the term does not specify the technology involved, so I coined the term &amp;quot;OLAP data mart&amp;quot; to identify a subset of data which is delivered in the form of an OLAP cube which may be accompanied by the relational database upon which it was built. To clarify, the relational database is specifically create and loaded with the subset of data and then the OLAP cube is built and processed to make the data available to the end-users via standard OLAP client tools.
&lt;/p&gt;&lt;h2&gt;Why build OLAP data marts?
&lt;/h2&gt;&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Market_research"&gt;Market research&lt;/a&gt; companies sell data to their clients to make money.  To gain competitive advantage, market research providers like to &amp;quot;add value&amp;quot; to their data by providing systems that enhance analytics, thereby allowing clients to make best use of the data.  As such, &lt;a href="http://en.wikipedia.org/wiki/Olap_cube"&gt;OLAP cubes&lt;/a&gt; have become a standard way of delivering added value to clients. They can be built on-the-fly to hold specific data sets and meet particular needs and then hosted on a secure intranet site for remote access, or shipped to clients&amp;#39; own infrastructure for hosting.  Even better, they support a wide range of different tools for analytical purposes, including the ever popular &lt;a href="http://en.wikipedia.org/wiki/Microsoft_Excel"&gt;Microsoft Excel&lt;/a&gt;. 
&lt;/p&gt;&lt;h2&gt;Extension Attributes: The Challenge
&lt;/h2&gt;&lt;p&gt;One of the key challenges in building multiple OLAP data marts based on the same &amp;#39;template&amp;#39; is handling extension attributes.  These are attributes that meet the client&amp;#39;s specific reporting needs, but do not form part of the standard template.  Now clearly, these extension attributes have to come into the system via additional files and ultimately be added to relational tables so they can end up in the OLAP cube.  However, processing these files and filling dynamically altered tables with SSIS is a challenge as SSIS packages tend to break as soon as the database schema changes.
&lt;/p&gt;&lt;p&gt;There are two approaches to this: (1) dynamically build an SSIS package in memory to match the new database schema using C#, or (2) have the extension attributes provided as name/value pairs so the file&amp;#39;s schema does not change and can easily be loaded using SSIS.   The problem with the first approach is the complexity of writing an awful lot of complex C# code.  The problem of the second approach is that name/value pairs are useless to an OLAP cube; so they have to be pivoted back into a proper relational table somewhere in the data load process WITHOUT breaking SSIS.  How this can be done will be part of future blog entry.
&lt;/p&gt;&lt;h2&gt;What is involved in building an OLAP data mart?
&lt;/h2&gt;&lt;p&gt;There are a great many steps involved in building OLAP data marts on-the-fly.  The key point is that all the steps must be automated to allow for the production of multiple OLAP data marts per day (i.e. many thousands, each with its own specific data set and attributes).   
&lt;/p&gt;&lt;p&gt;Now most of these steps have a great deal in common with standard data warehouse practices. The key difference is that the databases are all built to order.  The only permanent database is the metadata database (shown in orange) which holds all the metadata needed to build everything else (i.e. client orders, configuration information, connection strings, client specific requirements and attributes &lt;i&gt;etc.&lt;/i&gt;).  The staging database (shown in red) has a short life: it is built, populated and then ripped down as soon as the OLAP Data Mart has been populated.  In the diagram below, the &lt;b&gt;OLAP data mart&lt;/b&gt; comprises the two blue components: the Data Mart which is a relational database and the OLAP Cube which is an OLAP database implemented using Microsoft Analysis Services (SSAS).  The client may receive just the OLAP cube or both components together depending on their reporting requirements. 
&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/DynamicOLAP.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/DynamicOLAP.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;So, in broad terms the steps required to fulfil a client order are as follows:
&lt;/p&gt;&lt;h3&gt;Step 1: Prepare metadata
&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create a set of database names unique to the client&amp;#39;s order 
&lt;/li&gt;&lt;li&gt;Modify all package connection strings to be used by SSIS to point to new databases and file locations.
&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 2: Create relational databases
&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create the staging and data mart relational databases using dynamic SQL and set the database recovery mode to SIMPLE as we do not need the overhead of logging anything
&lt;/li&gt;&lt;li&gt;Execute SQL scripts to build all database objects (tables, views, functions and stored procedures) in the two databases
&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 3: Load staging database
&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Use SSIS to load all data files into the staging database in a parallel operation
&lt;/li&gt;&lt;li&gt;Load extension files containing name/value pairs.  These will provide client-specific attributes in the OLAP cube.
&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 4: Load data mart relational database
&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Load the data from staging into the data mart relational database, again in parallel where possible
&lt;/li&gt;&lt;li&gt;Allocate surrogate keys and use SSIS to perform surrogate key lookup during the load of fact tables
&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 5: Load extension tables &amp;amp; attributes
&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Pivot the extension attributes from their native name/value pairs into proper relational tables
&lt;/li&gt;&lt;li&gt;Add the extension attributes to the views used by OLAP cube
&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 6: Deploy &amp;amp; Process OLAP cube
&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Deploy the OLAP database directly to the server using a C# script task in SSIS 
&lt;/li&gt;&lt;li&gt;Modify the connection string used by the OLAP cube to point to the data mart relational database
&lt;/li&gt;&lt;li&gt;Modify the cube structure to add the extension attributes to both the data source view and the relevant dimensions
&lt;/li&gt;&lt;li&gt;Remove any standard attributes that not required 
&lt;/li&gt;&lt;li&gt;Process the OLAP cube
&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 7: Backup and drop databases
&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Drop staging database as it is no longer required
&lt;/li&gt;&lt;li&gt;Backup data mart relational and OLAP database and ship these to the client&amp;#39;s infrastructure 
&lt;/li&gt;&lt;li&gt;Drop data mart relational and OLAP database from the build server
&lt;/li&gt;&lt;li&gt;Mark order complete 
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Start processing the next order, &lt;i&gt;ad infinitum&lt;/i&gt;.
&lt;/p&gt;&lt;p&gt;So my future blog posts and my forthcoming session at the &lt;a href="http://www.sqlbits.com/"&gt;SQLBits conference&lt;/a&gt; will all focus on some of the more interesting aspects of building OLAP data marts on-the-fly such as handling the load of extension attributes and how to dynamically alter the structure of an OLAP cube using C#.&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=15341" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSIS/default.aspx">SSIS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQLBits/default.aspx">SQLBits</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2011/02/06/building-dynamic-olap-data-marts-on-the-fly.aspx</feedburner:origLink></item><item><title>Microsoft Access: an elegant solution to Data Warehouse metadata</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/s5C57MRT1-E/microsoft-access-an-elegant-solution-to-data-warehouse-metadata.aspx</link><pubDate>Sun, 14 Feb 2010 09:01:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:13087</guid><dc:creator>DrJohn</dc:creator><slash:comments>2</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=13087</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2010/02/14/microsoft-access-an-elegant-solution-to-data-warehouse-metadata.aspx#comments</comments><description>&lt;p&gt;Before you send me flame mail telling me I must be off my rocker, I am not proposing Microsoft Access store any data!  We all know that its JET-based database engine has severe limitations in terms of speed and scalability.  No, what I am proposing is that Access is used as is a very quick way for you to deliver an easy-to-use front-end for your business users to edit metadata which is actually stored in a SQL Server back-end database.
&lt;/p&gt;&lt;p&gt;Whether you have a classic data warehouse architecture, or some botched system that evolved over the years, you will no doubt have some metadata that is vital to your data warehouse yet did not come from any source system.  Usually this data needs to be changed by business users on an infrequent basis.  
&lt;/p&gt;&lt;p&gt;In big data warehouse (DWH) implementations, where money is no object, you can take the time to build an entire web-based application to edit and manage metadata.  This is fantastic for those with deep pockets and long delivery timescales, but realistically not every customer can afford such luxuries.  On the other hand Microsoft Access provides a quick and inexpensive way to deliver a mechanism to edit metadata using &lt;b&gt;Linked Tables&lt;/b&gt;.  This blog provides a tutorial on how to create a front-end metadata editing tool with Microsoft Access and also provides a useful starting template for you to build your own metadata editor.  So here goes.
&lt;/p&gt;&lt;h2&gt;Target Architecture
&lt;/h2&gt;&lt;p&gt;Before showing how to build your first front-end using my template, let&amp;#39;s talk about the technical architecture.  
&lt;a href="http://sqlblogcasts.com/blogs/drjohn/MSAccessTechArch.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/MSAccessTechArch.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The best approach is to store your metadata in a separate database.  This offers better control over security as users can be given full permission on the metadata database but limited rights to the other databases in the data warehouse.&amp;nbsp;  Also, the metadata database can have full recovery model, so it can be restored to any point; something that is not always applied to a staging database.  However, your architecture may be a sub-set of this.  Needless to say, the template I provide will prove useful in any situation.
&lt;/p&gt;&lt;h2&gt;Example front-end
&lt;/h2&gt;&lt;p&gt;The following screen shots shows exactly what can be achieved using Microsoft Access.  Now these are actually very crude by comparison to what can be achieved by proper MS-Access developers, but they are quick and easy to build for those with limited time and skills. Also business users find them easy to understand.  
&lt;/p&gt;&lt;p&gt;My example screens allow the business user to edit a Region hierarchy which becomes a dimension in the OLAP cube.  The region hierarchy is roughly geographical in nature, but it is business focused and not related to geo-political boundaries and therefore not be available in any source system; hence the need to hold this data in the data warehouse.  The hierarchy has three-levels: the top level has &lt;b&gt;Regions&lt;/b&gt;, the mid-tier has &lt;b&gt;Locations&lt;/b&gt; and the bottom level holds &lt;b&gt;Business Units&lt;/b&gt;.  Clearly we could have more levels, but this is sufficient for my example.  
&lt;/p&gt;&lt;p&gt;Been able to edit this kind of structure delivers a lot of power to your business users as they are now able to control how all reports are presented to end-users and how numbers roll-up in the OLAP cube.  Nothing to be sneezed at!  
&lt;/p&gt;&lt;p&gt;The tables in the metadata database that support the region hierarchy are normalized for editing and de-normalized by a view when been sucked into the DWH for use in the OLAP cube.  So our MS-Access database has to edit the following SQL Server tables:
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/DatabaseSchema.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/DatabaseSchema.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Main Menu
&lt;/h3&gt;&lt;p&gt;The main menu is the first thing the user sees.  This is their jumping off point for editing the metadata.  Of course the screen must be in their language, not techno-babble!  
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/MainMenu.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/MainMenu.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Edit Regions
&lt;/h3&gt;&lt;p&gt;Clicking &amp;quot;Regions&amp;quot; will show the following screen.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/EditRegions.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/EditRegions.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Although crude, this allows the user to a) change the name of a region and b) add new regions. Foreign key relationships or triggers in the underlying SQL Server database should stop users deleting rows unless you want them too.  
&lt;/p&gt;&lt;p&gt;In a classic DWH implementation, the user should indicate that a region is defunct by changing its status.  In my simple example, they do so by deleting the row.  Both approaches can be implemented using MS-Access, it is just a matter of design.
&lt;/p&gt;&lt;h3&gt;Edit Locations
&lt;/h3&gt;&lt;p&gt;The&lt;b&gt; Edit Locations &lt;/b&gt;form is more sophisticated as it provides drop-down lists for the user to select the region (i.e. from what the user entered on the &lt;b&gt;Edit Regions&lt;/b&gt; form).  This is because the metadata tables are normalized for editing and de-normalized by a view when been sucked into the OLAP cube.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/EditLocation.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/EditLocation.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Edit Location to Business Unit Mapping
&lt;/h3&gt;&lt;p&gt;The final screen allows the user to map their business data to the bottom level of the regions hierarchy.  For my client, this screen related locations to the identifiers used by the finance department to classify all revenue and costs.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/EditLocationMapping.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/EditLocationMapping.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;The easy way to create Linked Tables
&lt;/h2&gt;&lt;p&gt;In the template I provide a very simple mechanism to help you create your linked tables as well as switching between servers (i.e. between test and production database servers).  However, if you are new to MS-Access you will not appreciate the pain of creating and managing them manually, so let&amp;#39;s create a linked table the standard way first.
&lt;/p&gt;&lt;p&gt;To create a linked table through MS-Access, you go to the &lt;b&gt;External Data&lt;/b&gt; tab and click &lt;b&gt;More&lt;/b&gt; and select &lt;b&gt;ODBC Connection&lt;/b&gt; as shown below. 
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/ExternalDataODBCConnection.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/ExternalDataODBCConnection.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;You next select &lt;b&gt;Link to a data source by creating a linked table&lt;/b&gt; and click OK.  This will display the &lt;b&gt;Select Data Source &lt;/b&gt;dialog.  Now select your data source or create a new ODBC connection file.  Be careful to select the correct SQL Server Client Library for your version of SQL Server.  For example:
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/SQLServerNativeClient.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/SQLServerNativeClient.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Once you have created your ODBC connection, MS-Access will show you a list of all the tables in your SQL Server database where you can select multiple tables to link.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/ListAllTablesDialog.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/ListAllTablesDialog.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Click OK and the tables are linked.  Well that seemed easy enough, so where is the pain?  Well the pain comes when you want to switch servers.  The connection string for each table is held in the metadata associated with the table.  It is far too easy to connect different tables to different servers during development (e.g. some to localhost, others to a dev server etc.), secondly the Linked Table Manager provided in MS-Access is not the most intuitive UI for changing the database links.  Indeed it does not tell you on which server the tables reside!  For that, you need to hover over the linked table in the Navigation Pane as shown below.  Not too convenient!
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/ConnectionString.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/ConnectionString.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The other thing about these newly linked tables is that the schema is displayed, which means the first thing you will do is edit the name displayed in MS-Access. Again a pain if you have to drop and recreate tables when switching between servers.
&lt;/p&gt;&lt;h2&gt;Change server and create linked tables all in one step
&lt;/h2&gt;&lt;p&gt;My template provides a far simpler mechanism to simultaneously change server and re-create all the linked tables in one step.  You simply edit the &lt;b&gt;SourceServers&lt;/b&gt; table and fill in names and descriptions of all your servers.  
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/SourceServers.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/SourceServers.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;You then edit the &lt;b&gt;LinkedTables&lt;/b&gt; table and fill in the names of the tables you want to link along with the name of the database in which they are stored.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/LinkedTables.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/LinkedTables.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Then select &lt;b&gt;Change Server&lt;/b&gt; from the main menu and a list of servers will appear.  Simply select your server and click OK.  The code will delete all existing linked tables and then re-create them based on the information provided in the &lt;b&gt;LinkedTables&lt;/b&gt; table.  So changing between development and production servers is now extremely easy!
&lt;/p&gt;&lt;h2&gt;Basic Editing
&lt;/h2&gt;&lt;p&gt;The top level of the hierarchy is Region and is held as a simple list of names with an identity column.  We only need a basic editor for the user to edit this list, so we will use the default datasheet view provided by MS-Access.  To invoke the basic editor, simply double-click on the Region table and you will see the datasheet view (displayed below). Remember, if the left-hand Navigation Pane is not visible, simply click F11. 
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/EditRegions.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/EditRegions.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;Editor with drop-down selections
&lt;/h2&gt;&lt;p&gt;Our &lt;b&gt;Location&lt;/b&gt; table has a foreign key relationship with the &lt;b&gt;Region&lt;/b&gt; table.  Rather than have our users remember a lot of meaningless IDs, we want to provide them with a drop down menu.  To do this, click on the &lt;b&gt;Location&lt;/b&gt; table in the &lt;b&gt;Navigation Pane&lt;/b&gt; and then open the &lt;b&gt;Create&lt;/b&gt; tab and select the &lt;b&gt;Forms Wizard&lt;/b&gt; as shown below.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/FormWizard1.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/FormWizard1.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Next you will see the Form Wizard&amp;#39;s field selection dialog. Select all fields.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/FormWizardFieldSelection.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/FormWizardFieldSelection.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;On the next &lt;b&gt;Layout&lt;/b&gt; selection dialog, select &lt;b&gt;Tabular&lt;/b&gt;.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/FormWizardLayout.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/FormWizardLayout.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;On the &lt;b&gt;Style&lt;/b&gt; dialog, pick your preferred style.  I recommend sticking to the &lt;b&gt;Office&lt;/b&gt; theme if you are unsure.  On the final dialog, name the new form and click &lt;b&gt;Finish&lt;/b&gt;.
&lt;/p&gt;&lt;p&gt;You will now see the basic Location editing form ready for you to enter data.  It looks much better than the basic form we created for Regions, but has the problem that the user has to remember the RegionID in order to make an entry.  
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/SwitchToDesignView.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/SwitchToDesignView.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We get around this by changing the RegionID field to use a combo box.  Switch into design mode using the View option on the Home tab and select the RegionID field.  Right-click and select change to combo box. 
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/RegionID_1_ComboBox.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/RegionID_1_ComboBox.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Now change the Row Source property by clicking the three dots in the Property Sheet (press F4 if this is not visible).
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/RegionID_2_RowSource.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/RegionID_2_RowSource.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Use the query designer to create the query:
&lt;/p&gt;&lt;p style="margin-left:36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;SELECT Region.RegionID, Region.RegionName FROM Region;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This SQL should be displayed in the Row Source property once you exit the designer.
&lt;/p&gt;&lt;p&gt; Finally change the Column Count property to 2 and set the column widths to 0cm;4cm  
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/RegionID_3_ColumnCount.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/RegionID_3_ColumnCount.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This has the effect of hiding the RegionID from the user as shown below.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/EditLocation.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/EditLocation.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Edit Location Mapping  table
&lt;/h2&gt;&lt;p&gt;The LocationMapping table maps business unit IDs from the source finance system to locations.  So here the drop down list we provide to the user has to come from the source finance system.  As this is a data warehouse, we have already extracted and cleaned that data with SSIS and written it into the staging database.  So we simply need to create a linked table to the relevant table in the staging database.  Again this is easily done using the LinkedTables table as this has a SourceDatabase column as shown below.  Of course you will need to click the Change Server button to create the new linked table.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/LinkedTables.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/LinkedTables.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Using the same technique as we did with the RegionID column in the Location form, we can create a form containing two drop-down lists as shown below. 
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/EditLocationMapping.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/EditLocationMapping.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Creating the Main Menu
&lt;/h2&gt;&lt;p&gt;When the user first opens the database, you want to display a menu of options so they can find things easily.  To create a new form, simply choose &lt;b&gt;Form&lt;/b&gt; on the &lt;b&gt;Create&lt;/b&gt; tab.  Then switch to design mode and expand the detail section to reveal a white cross-hatched area.  As you are in design mode, you will see the &lt;b&gt;Form Design Tools&lt;/b&gt; tabs on the ribbon.  Select &lt;b&gt;Design&lt;/b&gt; tab and click &lt;b&gt;Button&lt;/b&gt;.  Now highlight an area of form and draw a button.  When a dialog pops up, simply click &lt;b&gt;Cancel&lt;/b&gt; as we do not want any standard option.  Open the &lt;b&gt;Property Sheet&lt;/b&gt; and give the button a sensible &lt;b&gt;Name&lt;/b&gt; on the &lt;b&gt;Other &lt;/b&gt;tab (e.g. cmdRegion).   On the &lt;b&gt;Event&lt;/b&gt; tab, select [Event Procedure] in the on-click event and click the three dots box to open the Visual Basic editor.  
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/VB_DoCmdOpenTable.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/VB_DoCmdOpenTable.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;To open the region table directly for editing (i.e. because we do not need a special form) we use the OpenTable command as follows:
&lt;/p&gt;&lt;p style="margin-left:36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;DoCmd.OpenTable &amp;quot;Region&amp;quot;, acViewNormal, acEdit
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;We now repeat the steps to create buttons for our other forms.  However, as we have created special forms to edit these tables we need to use the OpenForm command as follows:
&lt;/p&gt;&lt;p style="margin-left:36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;DoCmd.OpenForm &amp;quot;Location&amp;quot;, acNormal, , , acFormEdit
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;For some obscure reason MS-Access still uses macros to achieve certain tasks.  In order to have the main menu appear when the user first opens the database, you need to create macro called AutoExec which does this.
&lt;/p&gt;&lt;p&gt;&lt;a href="http://sqlblogcasts.com/blogs/drjohn/AutoExec.png"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/AutoExec.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;User Permissions
&lt;/h2&gt;&lt;p&gt;If you have a separate metadata database, then your users only need read-write permissions to that database.  If the MS-Access database uses other tables to populate drop-down lists, then the user will need read-only access to those tables.  This can be managed on a table by table basis or by simply adding the user to a database role with db_datareader and/or db_datawriter roles. 
&lt;/p&gt;&lt;h2&gt;Gotha: Tables must have a Primary Key 
&lt;/h2&gt;&lt;p&gt;MS-Access can only edit tables that have primary keys defined. If no primary key is defined, then you will find that your form is locked in read-only mode with no indication whatsoever as to why you cannot edit the data.    For me this was a painful learning curve, as I had most of my tables with primary keys but the odd one or two without.  Given the lack of feedback from MS-Access as to why the forms were locked in read-only mode, it was quite some time until that I realised what caused the problem.
&lt;/p&gt;&lt;h2&gt;Deployment
&lt;/h2&gt;&lt;p&gt;Clearly your business users need MS-Access installed on their desktop in order to use you new metadata editor.  I would recommend developing the database using the same version of MS-Access as your users have installed.  Although my screen shots are of MS-Access 2007, this application can be built using MS-Access 2003 as well.
&lt;/p&gt;&lt;p&gt;Although convenient, I would not recommend using a file share to deploy the database as I have found that slow VPN connections can corrupt the MS-Access database making it unusable for everyone.  Instead, have the users copy the database to their desktop or install on their PC to a standard location.  You could even write an installer, although that is rather over the top as a simple batch file would do!
&lt;/p&gt;&lt;p&gt;The other thing to be careful about is the version of SQL Client libraries on the user&amp;#39;s desktop.  I would recommend using what is already available rather than requiring a separate install.  Clearly testing on several machines will highlight any issues in this area.  If you need to change the version of SQL Client used by my template, simply edit the ODBC_DRIVER constant in the VB module called Common.
&lt;/p&gt;&lt;h2&gt;Replication of metadata to the staging database
&lt;/h2&gt;&lt;p&gt;If you are not happy using cross-database joins in your stored procedures, you may well need to replicate the metadata to the staging database for use in the data warehouse.  This can be done in a number of ways using SSIS or SQL replication. However, this is a topic outside the scope of this blog entry.
&lt;/p&gt;&lt;h2&gt;MS-Access Template 
&lt;/h2&gt;&lt;p&gt;The MS-Access Template and SQL scripts to create the demo region hierarchy is available for download here: &lt;a href="http://sqlblogcasts.com/blogs/drjohn/Metadata_Editor.zip"&gt;Metadata_Editor.zip&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;p&gt;Dr. John&lt;/p&gt;&lt;p&gt;&lt;a href="http://uk.linkedin.com/in/drjohntunnicliffe"&gt;&lt;img src="http://sqlblogcasts.com/blogs/drjohn/linkedin_logo.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=13087" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2010/02/14/microsoft-access-an-elegant-solution-to-data-warehouse-metadata.aspx</feedburner:origLink></item><item><title>SSAS: Microsoft release fix for “Kerberos killing MDX” issue  </title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/9nWuN21JQ5s/ssas-microsoft-release-fix-for-kerberos-killing-mdx-issue.aspx</link><pubDate>Sat, 18 Jul 2009 15:28:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:11997</guid><dc:creator>DrJohn</dc:creator><slash:comments>1</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=11997</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2009/07/18/ssas-microsoft-release-fix-for-kerberos-killing-mdx-issue.aspx#comments</comments><description>&lt;p&gt;In a &lt;a href="http://sqlblogcasts.com/blogs/drjohn/archive/2009/03/28/kerberos-kills-large-mdx-queries-on-windows-server-2008-ssas.aspx"&gt;previous post&lt;/a&gt; I reported how small MDX queries worked fine when client and server were Windows Vista/Windows Server 2008 but large MDX queries died due to the connection been forcibly closed by the transport layer. It turned out that this issue was due to a bug in the Kerberos.dll on these AES aware operating systems. AES = Advanced Encryption Standard. &lt;/p&gt;
&lt;p&gt;Microsoft have how&amp;nbsp;&lt;a href="http://support.microsoft.com/kb/969083"&gt;released a hot fix&lt;/a&gt;&amp;nbsp;for this issue.&amp;nbsp; Read &lt;a href="http://blogs.msdn.com/psssql/archive/2009/04/03/errors-may-occur-after-configuring-analysis-services-to-use-kerberos-authentication-on-advanced-encryption-standard-aware-operating-systems.aspx"&gt;John Desch&amp;#39;s blog post&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;Note that this bug is not present in the Windows Server 2008 R2 or Windows 7 release.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=11997" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/MDX/default.aspx">MDX</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2009/07/18/ssas-microsoft-release-fix-for-kerberos-killing-mdx-issue.aspx</feedburner:origLink></item><item><title>SSAS: Kerberos kills ‘large’ MDX queries on Windows Server 2008</title><link>http://feedproxy.google.com/~r/SparksFromTheAnvil/~3/lEHbfvtMrRE/kerberos-kills-large-mdx-queries-on-windows-server-2008-ssas.aspx</link><pubDate>Sat, 28 Mar 2009 23:05:00 GMT</pubDate><guid isPermaLink="false">fa8c4e8e-46a3-4193-8264-2c1a9cb3475d:11493</guid><dc:creator>DrJohn</dc:creator><slash:comments>9</slash:comments><wfw:commentRss>http://sqlblogcasts.com/blogs/drjohn/rsscomments.aspx?PostID=11493</wfw:commentRss><comments>http://sqlblogcasts.com/blogs/drjohn/archive/2009/03/28/kerberos-kills-large-mdx-queries-on-windows-server-2008-ssas.aspx#comments</comments><description>&lt;p&gt;Kerberos is nasty! I have had several encounters with Kerberos and none of them have been pleasant. I try to avoid Kerberos like try to avoid the dentist. However, some projects demand that Kerberos authentication be used to cater for the &amp;#39;third hop&amp;#39; and then the pain begins. &lt;/p&gt;
&lt;p&gt;The symptoms of my latest encounter were somewhat odd. Local MDX queries worked fine, but queries performed over the network failed with the message: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Executing the query ...&lt;br /&gt;&lt;span style="COLOR:red;"&gt;The connection either timed out or was lost.&lt;br /&gt;Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.&lt;br /&gt;An existing connection was forcibly closed by the remote host&lt;br /&gt;&lt;/span&gt;Execution complete &lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Of course the error message does not tell us anything useful. Just that someone does not like us today! &lt;/p&gt;
&lt;p&gt;At first we thought there was a fault with the MDX query. But no, the MDX query ran fine against the local development server and also ran fine against the production server when run in SQL Server Management Studio in local mode (i.e. not across the network). But as soon as we ran the query across the network, we got the error. &lt;/p&gt;
&lt;p&gt;Suspecting a hardware fault on the brand new server, the IT support team checked out the memory and changed the network cards. No change; the queries still failed. &lt;/p&gt;
&lt;p&gt;Anyone familiar with SQL Server Analysis Services (SSAS) knows that it uses a Windows-based security model (i.e. the user must have Windows account in order to connect to the OLAP database). Unfortunately, this becomes a problem when the user&amp;#39;s credentials need to be passed from machine to machine before finally arriving at the OLAP server. Basically the NTLM protocol does not support delegation across more than two hops. &lt;/p&gt;
&lt;p&gt;To cater for the third &amp;#39;hop&amp;#39; you have to co-opt the help of the &amp;#39;dark side&amp;#39;: i.e. Kerberos and SPNs. Servers have to be &amp;#39;registered for delegation&amp;#39; in Active Directory and SPNs have to be set up to configure Kerberos. This is a black art and my colleague and I have the battle scars to prove it! &lt;/p&gt;
&lt;p&gt;Our configuration was not unusual. Users connected to a web server running SharePoint 2007 and SQL Server Reporting Services (SSRS). SSRS then queries SQL Server Analysis Services (SSAS) database which resides on the backend &amp;#39;data server&amp;#39;. The complication occurs when users connect over the internet; they are authenticated by Microsoft ISA server which passes their credentials on to the web server which in turn passes their credentials to SSRS which in turn passes their credentials on to SSAS. &lt;/p&gt;
&lt;p&gt;Now, this infrastructure was working fine in the current SQL Server 2005 / Windows Serve 2003 implementation. However, the new SQL Server 2008 / Windows Server 2008 implementation was having trouble with a single hop, so we were in big trouble! &lt;/p&gt;
&lt;p&gt;Suspecting a corrupt installation of SSAS, we did a re-installation of the whole SQL Server 2008 suite, but the MDX queries still failed. So next we did a fresh install of the Windows Server 2008 operating system along with SQL Server 2008, but the MDX queries still failed! &lt;/p&gt;
&lt;p&gt;At this point we still believed that all MDX queries failed. But then I observed that the filters on the SSRS reports were been populated, whereas running the main report query generated the same ugly error message. &lt;/p&gt;
&lt;p&gt;Been convinced my MDX was at fault, I started a trace of activity on the Analysis Services service which showed that small MDX queries worked fine (all the relevant log entries were present) whereas, large MDX queries failed and the only log entry was an &amp;quot;Audit Logout notification&amp;quot; event. &lt;/p&gt;
&lt;p&gt;I started to play with the MDX and found that if I padded out a very simple query with comments it started to fail around the 1096 character mark i.e. simply adding /******/ until the whole statement was over 1kB caused the query to fail! Clearly something major was going wrong! &lt;/p&gt;
&lt;p&gt;Still believing it to be a hardware or software implementation error, we proceeded to install SQL Server 2008 OLAP database on another identical box. No problem! MDX of any size worked fine. So it must be a hardware or software implementation fault???? &lt;/p&gt;
&lt;p&gt;After much scratching of his head, my good friend and colleague Eric Moutell eventually announced that the only difference between the two machines is that one had been set up with SPN entries to allow Kerberos authentication. So he deleted the entries, rebooted the world, rebooted the world again and finally any size MDX query worked on the original box. Ah ha! We were getting somewhere. So now we knew that nasty old Kerberos was having a laugh at our expense! &lt;/p&gt;
&lt;p&gt;We got in contact with Microsoft support and after sending detailed information about the bug and several gigabytes of server logs, they eventually admitted we had found a bug in Windows Server 2008 which they have agreed to fix! &lt;/p&gt;
&lt;p&gt;For those of you experiencing a similar problem, I reproduce the email from Microsoft support which you may find useful. In our environment, the server is running Windows Server 2008 64-bit with Microsoft SQL Server 2008 with the latest cumulative update patch CU3. The client machines we tried were either Windows Server 2008 64-bit or 32-bit running Microsoft SQL Server 2008 CU3. &lt;/p&gt;&lt;pre&gt;&lt;code&gt;From: Camino De Vicente Rodriguez&lt;br /&gt;Sent: 16 March 2009 13:58&lt;br /&gt;Subject: RE: Your case with Microsoft (SRZ090205000308)
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;Escalation engineers have confirmed that is a problem on &lt;br /&gt;Kerberos.dll related to encryption with AES on Windows 2008 and Vista. &lt;br /&gt;They have reported to the Product Group and, &lt;br /&gt;after analyzing it, they have accepted to fix it.
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;The estimated time for the fix is May &lt;br /&gt;(it is required two month cycle hotfix test pass).
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;I am sending you the Workarounds if you cannot wait until May:
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;If Kerberos authentication is a requirement, run Analysis Services &lt;br /&gt;on a Windows 2003 Server, since Windows 2003 Server is not AES aware. 
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;Use Windows 2003 Server, Windows XP, or Windows 2000 Server &lt;br /&gt;to run client applications that will be connecting to the &lt;br /&gt;Analysis Server configured for Kerberos authentication and running on Windows 2008. &lt;br /&gt;Since these operating systems are not AES aware, &lt;br /&gt;that will avoid use of AES for encryption/decryption. 
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;Avoid configuring the Analysis Server to use Kerberos &lt;br /&gt;Authentication, since this will result in the AES &lt;br /&gt;not being used for encryption/decryption 
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;Add &amp;quot;;SSPI=NTLM&amp;quot; or &amp;quot;;Integrated Security=SSPI&amp;quot; to the connection string, &lt;br /&gt;which will force use of NTLM and avoid use of AES for &lt;br /&gt;encryption/decryption 
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;Best regards,
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;Camino de Vicente&lt;br /&gt;EMEA GTSC Development Support Engineer
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://sqlblogcasts.com/aggbug.aspx?PostID=11493" width="1" height="1"&gt;</description><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblogcasts.com/blogs/drjohn/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><feedburner:origLink>http://sqlblogcasts.com/blogs/drjohn/archive/2009/03/28/kerberos-kills-large-mdx-queries-on-windows-server-2008-ssas.aspx</feedburner:origLink></item></channel></rss>
