<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Microsoft Bob</title><link>http://blogs.msdn.com/microsoftbob/default.aspx</link><description>NOTE: The views expressed on this blog are my own and may not reflect the views of Microsoft</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Now a SQL Master</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/11/21/now-a-sql-master.aspx</link><pubDate>Sat, 21 Nov 2009 19:25:07 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9926794</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9926794.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9926794</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9926794</wfw:comment><description>After a long and painful process, I have finally achieved this.&amp;#160;&amp;#160; Was it worth it, would I do it again?&amp;#160; Absolutely.&amp;#160; But please don’t call me Master Bob, Microsoft Bob is fine… I am doing quite a bit more work with my simulation database...(&lt;a href="http://blogs.msdn.com/microsoftbob/archive/2009/11/21/now-a-sql-master.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9926794" width="1" height="1"&gt;</description></item><item><title>Trying to catch up</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/10/06/trying-to-catch-up.aspx</link><pubDate>Tue, 06 Oct 2009 17:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9903868</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9903868.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9903868</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9903868</wfw:comment><description>&lt;P&gt;I apologize as I notice there are some inquiries related to code posted.&amp;nbsp; I should probably set expectations about this, as I am not the typical Microsoft employee with a MSDN blog.&amp;nbsp; Most of the other folks with MSDN blogs are in the product teams and blogging is part of their job.&amp;nbsp; With me, it is an extra activity and my real job is being&amp;nbsp;committed 24x7 to a high profile customer which takes priority over all my other professional activities.&amp;nbsp; I provide this blog as a way to share with the community, but there is no committment implied to fix any issues that people may find in the code or respond quickly to questions.&lt;/P&gt;
&lt;P&gt;Depending on customer situation, I may have time to frequently post as I did in&amp;nbsp;July/August posting about&amp;nbsp;a dozen articles, othertimes like this last month, customer issues take priority and I ma not post at all.&lt;/P&gt;
&lt;P&gt;I apologize for not being able to provide quicker turn-around on inquiries and will try to catch up with the questions/requests over the next week or two.&lt;/P&gt;
&lt;P&gt;Thanks for your patience.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9903868" width="1" height="1"&gt;</description></item><item><title>Data-mining the Web for Fun [and Profit??]</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/24/data-mining-the-web-for-fun-and-profit.aspx</link><pubDate>Mon, 24 Aug 2009 23:48:02 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9882966</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9882966.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9882966</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9882966</wfw:comment><description>&lt;p&gt;I’m trying to get more interaction on my blog by posing more provocative titles...&amp;#160; This weekend I downloaded the last 10 years of Financial fundamental data for virtually all of the major AMEX, NYSE, and NASDAQ stocks currently traded, which resulted in a data table containing about 60,000 rows for 7,000 different equities (some equities are less than 10 years old, so not all have 10 years of history).&amp;#160; These are not historical stock quotes that you can download from Yahoo, but historical financial fundamentals of earnings, book value, return on equity.&amp;#160; This type of information is invaluable for historical analysis to find correlations between financial metrics and stock performance. To get the quality and quantity of information in electronic format could costs several hundred dollars from a typical investment subscription service.&lt;/p&gt;  &lt;p&gt;Curious? I’ll try to walk you through the process, but first an overview.&amp;#160; There is an amazing amount of semi-structured data on the web, just waiting to be sucked into databases in order to enable advanced analytical processing.&amp;#160; By semi-structured, I mean data that is organized in a tabular format, even though it may not be directly downloadable or available via a web service.&amp;#160; There is a preponderance of useful data stored in HTML tables that can be harvested out of a web request.&amp;#160; In my case, I wanted to see what effects earnings have on the profitability of entry/exit strategies used for as part of my doctoral research project involving a stock trading simulator.&amp;#160; MSN has this great feature called 10 year summary which provides earnings, book value, and other key metrics on an annual basis going back 10 years.&amp;#160; For example, you can view Microsoft’s history by going to &lt;a title="http://moneycentral.msn.com/investor/invsub/results/compare.asp?Page=TenYearSummary&amp;amp;Symbol=msft" href="http://moneycentral.msn.com/investor/invsub/results/compare.asp?Page=TenYearSummary&amp;amp;Symbol=msft"&gt;http://moneycentral.msn.com/investor/invsub/results/compare.asp?Page=TenYearSummary&amp;amp;Symbol=msft&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;This gives you the following information for MSFT (Microsoft&lt;/p&gt;  &lt;div id="wrapper" class="page9 region9"&gt;   &lt;div id="page"&gt;     &lt;div style="width: 462px; height: 558px" id="content"&gt;       &lt;div id="area2" class="region8 legacy"&gt;         &lt;table class="t1"&gt;&lt;tbody&gt;             &lt;tr class="r0"&gt;               &lt;th&gt;&amp;#160;&lt;/th&gt;                &lt;th&gt;Avg P/E&lt;/th&gt;                &lt;th&gt;Price/ Sales&lt;/th&gt;                &lt;th&gt;Price/ Book&lt;/th&gt;                &lt;th&gt;Net Profit Margin (%)&lt;/th&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/09&lt;/td&gt;                &lt;td&gt;13.40&lt;/td&gt;                &lt;td&gt;3.66&lt;/td&gt;                &lt;td&gt;5.35&lt;/td&gt;                &lt;td&gt;24.9&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/08&lt;/td&gt;                &lt;td&gt;16.30&lt;/td&gt;                &lt;td&gt;4.31&lt;/td&gt;                &lt;td&gt;6.94&lt;/td&gt;                &lt;td&gt;29.3&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/07&lt;/td&gt;                &lt;td&gt;19.90&lt;/td&gt;                &lt;td&gt;5.70&lt;/td&gt;                &lt;td&gt;8.89&lt;/td&gt;                &lt;td&gt;27.5&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/06&lt;/td&gt;                &lt;td&gt;21.70&lt;/td&gt;                &lt;td&gt;5.54&lt;/td&gt;                &lt;td&gt;5.85&lt;/td&gt;                &lt;td&gt;28.5&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/05&lt;/td&gt;                &lt;td&gt;23.60&lt;/td&gt;                &lt;td&gt;6.81&lt;/td&gt;                &lt;td&gt;5.53&lt;/td&gt;                &lt;td&gt;30.8&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/04&lt;/td&gt;                &lt;td&gt;35.70&lt;/td&gt;                &lt;td&gt;8.45&lt;/td&gt;                &lt;td&gt;4.15&lt;/td&gt;                &lt;td&gt;22.2&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/03&lt;/td&gt;                &lt;td&gt;36.50&lt;/td&gt;                &lt;td&gt;8.67&lt;/td&gt;                &lt;td&gt;4.25&lt;/td&gt;                &lt;td&gt;23.4&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/02&lt;/td&gt;                &lt;td&gt;62.60&lt;/td&gt;                &lt;td&gt;10.71&lt;/td&gt;                &lt;td&gt;5.62&lt;/td&gt;                &lt;td&gt;18.9&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/01&lt;/td&gt;                &lt;td&gt;45.90&lt;/td&gt;                &lt;td&gt;16.09&lt;/td&gt;                &lt;td&gt;8.31&lt;/td&gt;                &lt;td&gt;30.5&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/00&lt;/td&gt;                &lt;td&gt;53.50&lt;/td&gt;                &lt;td&gt;19.29&lt;/td&gt;                &lt;td&gt;10.22&lt;/td&gt;                &lt;td&gt;41.0&lt;/td&gt;             &lt;/tr&gt;           &lt;/tbody&gt;&lt;/table&gt;          &lt;br /&gt;          &lt;table class="t1" width="434"&gt;&lt;colgroup&gt;&lt;col class="c1" /&gt;&lt;/colgroup&gt;&lt;colgroup class="c2"&gt;&lt;/colgroup&gt;&lt;tbody&gt;             &lt;tr class="r0"&gt;               &lt;th&gt;&amp;#160;&lt;/th&gt;                &lt;th width="78"&gt;Book Value/ Share&lt;/th&gt;                &lt;th width="84"&gt;Debt/ Equity&lt;/th&gt;                &lt;th width="90"&gt;Return on Equity (%)&lt;/th&gt;                &lt;th width="104"&gt;Return on Assets (%)&lt;/th&gt;                &lt;th width="38"&gt;Interest Coverage&lt;/th&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/09&lt;/td&gt;                &lt;td width="78"&gt;$4.44&lt;/td&gt;                &lt;td width="84"&gt;0.15&lt;/td&gt;                &lt;td width="90"&gt;36.8&lt;/td&gt;                &lt;td width="104"&gt;18.7&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/08&lt;/td&gt;                &lt;td width="78"&gt;$3.97&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;48.7&lt;/td&gt;                &lt;td width="104"&gt;24.3&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/07&lt;/td&gt;                &lt;td width="78"&gt;$3.32&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;45.2&lt;/td&gt;                &lt;td width="104"&gt;22.3&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/06&lt;/td&gt;                &lt;td width="78"&gt;$3.99&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;31.4&lt;/td&gt;                &lt;td width="104"&gt;18.1&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/05&lt;/td&gt;                &lt;td width="78"&gt;$4.49&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;25.5&lt;/td&gt;                &lt;td width="104"&gt;17.3&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/04&lt;/td&gt;                &lt;td width="78"&gt;$6.89&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;10.9&lt;/td&gt;                &lt;td width="104"&gt;8.7&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/03&lt;/td&gt;                &lt;td width="78"&gt;$6.03&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;11.6&lt;/td&gt;                &lt;td width="104"&gt;9.2&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/02&lt;/td&gt;                &lt;td width="78"&gt;$4.87&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;10.3&lt;/td&gt;                &lt;td width="104"&gt;7.9&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/01&lt;/td&gt;                &lt;td width="78"&gt;$4.39&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;16.3&lt;/td&gt;                &lt;td width="104"&gt;13.1&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td&gt;06/00&lt;/td&gt;                &lt;td width="78"&gt;$3.92&lt;/td&gt;                &lt;td width="84"&gt;0.00&lt;/td&gt;                &lt;td width="90"&gt;22.8&lt;/td&gt;                &lt;td width="104"&gt;18.1&lt;/td&gt;                &lt;td width="38"&gt;NA&lt;/td&gt;             &lt;/tr&gt;           &lt;/tbody&gt;&lt;/table&gt;       &lt;/div&gt;     &lt;/div&gt;   &lt;/div&gt; &lt;/div&gt;  &lt;p&gt;Wouldn’t that be handy to have in your financial database?&amp;#160; Unfortunately, although MSN provides web services for downloading data, I couldn’t find one that provided this.&amp;#160; There are plenty of providers of financial stock information, including Yahoo.&amp;#160; Although Yahoo provides an abundance of fundamental data and historical quote information (see &lt;a title="http://www.gummy-stuff.org/Yahoo-data.htm" href="http://www.gummy-stuff.org/Yahoo-data.htm"&gt;http://www.gummy-stuff.org/Yahoo-data.htm&lt;/a&gt; for more info), they don’t provide fundamentals data such as Price/Earnings, Book Value on a historical basis.&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;There are some tools already available to help you interactively copy and paste data from the web directly into spreadsheets such as &lt;a title="http://www.inexp.com/table_extractor/default.aspx" href="http://www.inexp.com/table_extractor/default.aspx"&gt;http://www.inexp.com/table_extractor/default.aspx&lt;/a&gt; (DISCLAIMER: None of my recommendations, particularly those about third-party software constitute any endorsement by Microsoft Corporation).&amp;#160; However, I couldn’t find any tools to do mass-downloads where you can vary the query string based on parameters from a database.&lt;/p&gt;  &lt;p&gt;Here is a look at the raw HTML, for brevity sake, I’ve not included all of it, just that for the first table and the content immediately preceding and subsequent:&lt;/p&gt;  &lt;p&gt;&amp;lt;table class=&amp;quot;t1&amp;quot;&amp;gt;&amp;lt;col class=&amp;quot;c1&amp;quot; /&amp;gt;&amp;lt;colgroup span=&amp;quot;4&amp;quot; class=&amp;quot;c2&amp;quot; /&amp;gt;&amp;lt;tr class=&amp;quot;r0&amp;quot;&amp;gt;&amp;lt;th&amp;gt;&amp;amp;nbsp;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Avg P/E&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price/ Sales&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price/ Book&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Net Profit Margin (%)&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/09&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;13.40&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;3.66&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5.35&amp;lt;/td&amp;gt;    &lt;br /&gt;&amp;lt;td&amp;gt;24.9&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/08&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;16.30&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;4.31&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;6.94&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;29.3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/07&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;19.90&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5.70&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;8.89&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;27.5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/06&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;21.70&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5.54&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5.85&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;28.5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/05&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;23.60&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;6.81&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5.53&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;30.8&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/04&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;35.70&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;8.45&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;4.15&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;22.2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/03&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;36.50&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;8.67&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;4.25&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;23.4&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/02&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;62.60&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;10.71&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5.62&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;18.9&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/01&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;45.90&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;16.09&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;8.31&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;30.5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;06/00&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;53.50&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;19.29&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;10.22&amp;lt;/td&amp;gt;     &lt;br /&gt;&amp;lt;td&amp;gt;41.0&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&lt;/p&gt;  &lt;p&gt;Notice, that the symbol token and name are clearly indicated as part of the URL &lt;a title="http://moneycentral.msn.com/investor/invsub/results/compare.asp?Page=TenYearSummary&amp;amp;Symbol=msft" href="http://moneycentral.msn.com/investor/invsub/results/compare.asp?Page=TenYearSummary&amp;amp;Symbol=msft"&gt;http://moneycentral.msn.com/investor/invsub/results/compare.asp?Page=TenYearSummary&amp;amp;&lt;font color="#ff8000"&gt;Symbol=msft&lt;/font&gt;&lt;/a&gt;&lt;font color="#ff8000"&gt;.&lt;/font&gt; (this is a key enabler for our approach).&amp;#160; Furthermore, although using the “View Source” gives us a lot of “gobbly-gook”, note that the data is in HTML tables (another key enabler) and there are definitive identifying tags that surround the data.&amp;#160; So, what if we were to write an application that downloaded the content from the web, searched for the identifying tag that starts the table, parsed the table up to point where an ending tag is found and loaded into a database?&amp;#160; And what if we wanted to do that for every trading symbol on the AMEX, NYSE, and NASDAQ?&amp;#160; Does that sound like an impossible task?&amp;#160; Not, if you have a Saturday to spend on it, like I did.&amp;#160; That’s right I finished in 1 day, thanks mainly to the power of .NET and SQL, and God’s grace, not particularly due to special skills of my own.&lt;/p&gt;  &lt;p&gt;So, here goes, the check list on how to do it:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Define an infrastructure for defining the metadata (search tag to find the table, table columns, etc).&amp;#160; about the desired data to download.&amp;#160; In my case, I leveraged SQL Server to create some database tables and stored procedures. &lt;/li&gt;    &lt;li&gt;Define a component that examines the metadata given a URL and parameter for the query string and returns the metadata as well as receive the metadata, run the web query, and parse the data according to the metadata to return it in a format that can be inserted into a database. &lt;/li&gt;    &lt;li&gt;Build the user application that leverages the above infrastructure and components to inserts into the application-specific database. &lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;Step 1 – The Infrastructure for Defining the Metadata&lt;/h4&gt;  &lt;p&gt;The schema is relatively simple, we just need to be able to identify the URL, the replacement variables in the URL string, and what to look for in each table and how to map them to our database and to our columns.&amp;#160; Based on this, here is what I came up with.&amp;#160; Everything is varchar except the Ids and sequence fields which are INTs, so no sense in boring you with the full schema:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Dataminingthewebforfunandprofit_81BC/image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Dataminingthewebforfunandprofit_81BC/image_thumb.png" width="449" height="484" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Based on this table structure, here is the data that is defined to support downloading the MSN history data:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;WebUrl:&lt;/strong&gt;&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="0" width="412"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="106"&gt;&lt;strong&gt;&lt;em&gt;ColName&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td width="304"&gt;&lt;strong&gt;&lt;em&gt;ColValue&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;UrlId&lt;/td&gt;        &lt;td width="304"&gt;1&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;UrlString&lt;/td&gt;        &lt;td width="304"&gt;http://moneycentral.msn.com/investor/invsub/results/compare.asp?Page=TenYearSummary&amp;amp;Symbol=[Symbol]&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;SqlSchemaName&lt;/td&gt;        &lt;td width="304"&gt;load&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;SqlTableName&lt;/td&gt;        &lt;td width="304"&gt;Msn10YearSummary&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;SqlDatabaseName&lt;/td&gt;        &lt;td width="304"&gt;TradingOptimizer_v3&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;For the WebUrl table, we simply define the url for the money central 10 year summary along with a placeholder variable for the trading symbol ([Symbol] which will get replaced by the actual symbol when the query is run through the parser component.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;UrlVariable&lt;/strong&gt;&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="64"&gt;&lt;strong&gt;&lt;em&gt;ColName&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td width="64"&gt;&lt;strong&gt;&lt;em&gt;ColValue&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;UrlVariableId&lt;/td&gt;        &lt;td&gt;1&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;UrlId&lt;/td&gt;        &lt;td&gt;1&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;UrlVariableName&lt;/td&gt;        &lt;td&gt;[Symbol]&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;SqlColumnName&lt;/td&gt;        &lt;td&gt;Symbol&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;UrlVariable defines the collection of variables that can be used, which includes all of the variables in the webUrl.&amp;#160; This also provides a mapping back to the source SQL Columns.&amp;#160; For our scenario, it is overkill, since we only have 1 replacement variable, but if we had multple replacements, such as an effective date range that might vary based on the data, it would be useful.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;HtmlTable&lt;/strong&gt;:&amp;#160; For my scenario, I actually have 2 HTML Tables to match to the 2 different tables provided on the MSN site, but let’s just look at the first one.&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="0" width="76"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="64"&gt;ColName&lt;/td&gt;        &lt;td width="10"&gt;ColValue&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;HtmlTableId&lt;/td&gt;        &lt;td width="10"&gt;3&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;UrlId&lt;/td&gt;        &lt;td width="10"&gt;1&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;TableStartString&lt;/td&gt;        &lt;td width="10"&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Avg P/E&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price/ Sales&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price/ Book&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Net Profit Margin (%)&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;TableEndString&lt;/td&gt;        &lt;td width="10"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;TableSequence&lt;/td&gt;        &lt;td width="10"&gt;1&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;The Table Start String tells the parsing component what data to look for in order to identify the start of the table.&amp;#160; The Table End String indicates when the end of the table has been reached.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;HtmlTableColumn&lt;/strong&gt;:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="0" width="268"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="24"&gt;&lt;strong&gt;&lt;em&gt;HtmlTableColumnId&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td width="104"&gt;&lt;strong&gt;&lt;em&gt;ColumnSequence&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td width="64"&gt;&lt;strong&gt;&lt;em&gt;HtmlTableId&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td width="64"&gt;&lt;strong&gt;&lt;em&gt;ColumnHeader&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td width="10"&gt;&lt;strong&gt;&lt;em&gt;SqlColumnName&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="24"&gt;2&lt;/td&gt;        &lt;td width="104"&gt;1&lt;/td&gt;        &lt;td&gt;3&lt;/td&gt;        &lt;td&gt;Avg P/E&lt;/td&gt;        &lt;td width="10"&gt;AvgPe&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="24"&gt;3&lt;/td&gt;        &lt;td width="104"&gt;2&lt;/td&gt;        &lt;td&gt;3&lt;/td&gt;        &lt;td&gt;Price/Sales&lt;/td&gt;        &lt;td width="10"&gt;PriceSales&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="24"&gt;4&lt;/td&gt;        &lt;td width="104"&gt;3&lt;/td&gt;        &lt;td&gt;3&lt;/td&gt;        &lt;td&gt;Price/Book&lt;/td&gt;        &lt;td width="10"&gt;PriceBook&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="24"&gt;5&lt;/td&gt;        &lt;td width="104"&gt;4&lt;/td&gt;        &lt;td&gt;3&lt;/td&gt;        &lt;td&gt;Net Profit Magin (%)&lt;/td&gt;        &lt;td width="10"&gt;NetProfitMarginPct&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="24"&gt;13&lt;/td&gt;        &lt;td width="104"&gt;0&lt;/td&gt;        &lt;td&gt;3&lt;/td&gt;        &lt;td&gt;&amp;#160;&lt;/td&gt;        &lt;td width="10"&gt;EffectiveDate&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;This gives us the sequence for the data in the table along with the mappings to the SQL columns based on the column sequence and header.&amp;#160; For example, table item #1, Avg P/e maps to a SQL Column named AvgPe.&lt;/p&gt;  &lt;h4&gt;Step 2 – The Metadata Examiner/Parser Component&lt;/h4&gt;  &lt;p&gt;For this, we want to separate the metadata parsing from the actual data parsing.&amp;#160; The reason is simply performance, there is no reason to repeatedly parse the database to identify how to find and parse the desired html tables, we can do that on the initial instantiation to construct a schema and then reuse the schema for each instance of the data.&amp;#160; When I first prototyped this, I made the mistake of doing it all in one fail swoop, then had to refactor when considering the performance for doing the parsing for all 7,000 symbols I wanted to download.&lt;/p&gt;  &lt;p&gt;Based on this, I came up with the following class structure:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Dataminingthewebforfunandprofit_81BC/image_4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Dataminingthewebforfunandprofit_81BC/image_thumb_1.png" width="383" height="313" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Now, you might be wondering about all of the objects for accessing the data; For that I used LINQ-to-SQL and the diagram looks much like the SQL database diagram already shown in step 1.&amp;#160; There are a couple of simple stored procedures shown below (generated pretty much as is by my AGE tool (see &lt;a title="http://age.codeplex.com/" href="http://age.codeplex.com/"&gt;http://age.codeplex.com/&lt;/a&gt;) for doing the retrieval shown below:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;
/*
==========================================================================================
Author:        Bob L (Generated &lt;span class="kwrd"&gt;by&lt;/span&gt; Age)
&lt;span class="kwrd"&gt;Create&lt;/span&gt; &lt;span class="kwrd"&gt;date&lt;/span&gt;:    8/22/2009
Description:    Selects &lt;span class="kwrd"&gt;from&lt;/span&gt; UrlVariable
Example:        
==========================================================================================
*/
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [Web].[SelectUrlVariable]
  @findnull_SqlColumnName &lt;span class="kwrd"&gt;bit&lt;/span&gt; = 0,
  @find_UrlVariableId &lt;span class="kwrd"&gt;int&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
  @find_UrlId &lt;span class="kwrd"&gt;int&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
  @find_UrlVariableName &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(500) = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
  @find_SqlColumnName &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(128) = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; XACT_ABORT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;

/*
&lt;span class="rem"&gt;-- ****** DEBUG BEGIN *********&lt;/span&gt;
  &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @ParamVar &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(50)
  &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ParamVar = &lt;span class="str"&gt;'Test'&lt;/span&gt;
&lt;span class="rem"&gt;-- ****** DEBUG END *********&lt;/span&gt;
*/

    &lt;span class="rem"&gt;-- Want to add additional information to raiserror, so need to save ErrorID&lt;/span&gt;
    &lt;span class="rem"&gt;-- since next statement clears @@ERROR.&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @ErrorSave &lt;span class="kwrd"&gt;INT&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ErrorSave = 0

  &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 
        UrlVariableId,
        UrlId,
        UrlVariableName,
        SqlColumnName
  &lt;span class="kwrd"&gt;FROM&lt;/span&gt; 
        [UrlVariable]
  &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; 
        ([UrlVariableId]= @find_UrlVariableId &lt;span class="kwrd"&gt;OR&lt;/span&gt; @find_UrlVariableId &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; )
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; ([UrlId]= @find_UrlId &lt;span class="kwrd"&gt;OR&lt;/span&gt; @find_UrlId &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; )
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; ([UrlVariableName]= @find_UrlVariableName &lt;br /&gt;&lt;span class="kwrd"&gt;OR&lt;/span&gt; @find_UrlVariableName &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; )
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; ([SqlColumnName]= @find_SqlColumnName &lt;br /&gt;&lt;span class="kwrd"&gt;OR&lt;/span&gt; (@find_SqlColumnName &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;br /&gt;&lt;span class="kwrd"&gt;AND&lt;/span&gt; @findnull_SqlColumnName= 0) &lt;span class="kwrd"&gt;OR&lt;/span&gt; ([SqlColumnName] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;br /&gt;&lt;span class="kwrd"&gt;AND&lt;/span&gt; @findnull_SqlColumnName= 1))
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ErrorSave = &lt;span class="preproc"&gt;@@ERROR&lt;/span&gt;

    &lt;span class="kwrd"&gt;IF&lt;/span&gt; @ErrorSave != 0
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
      &lt;span class="kwrd"&gt;RAISERROR&lt;/span&gt;(&lt;span class="str"&gt;'Failure on SELECT for table [UrlVariable] in &lt;br /&gt;PROCEDURE [SelectUrlVariable].  Error ID=%d.'&lt;/span&gt;, 10, 1, @ErrorSave)
      &lt;span class="kwrd"&gt;RETURN&lt;/span&gt;(@ErrorSave)
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
&lt;span class="kwrd"&gt;END&lt;/span&gt;

&lt;span class="kwrd"&gt;GO&lt;/span&gt;

/*
==========================================================================================
Author:        Bob L (Generated &lt;span class="kwrd"&gt;by&lt;/span&gt; Age)
&lt;span class="kwrd"&gt;Create&lt;/span&gt; &lt;span class="kwrd"&gt;date&lt;/span&gt;:    8/22/2009
Description:    Selects &lt;span class="kwrd"&gt;from&lt;/span&gt; Url
Example:        
==========================================================================================
*/
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [Web].[SelectWebUrl]
  @find_UrlId &lt;span class="kwrd"&gt;int&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
  @find_UrlString &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(500) = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
  @find_SqlSchemaName &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(128) = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
  @find_SqlTableName &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(128) = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
  @find_SqlDatabaseName &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(128) = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; XACT_ABORT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;

/*
&lt;span class="rem"&gt;-- ****** DEBUG BEGIN *********&lt;/span&gt;
  &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @ParamVar &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(50)
  &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ParamVar = &lt;span class="str"&gt;'Test'&lt;/span&gt;
&lt;span class="rem"&gt;-- ****** DEBUG END *********&lt;/span&gt;
*/

    &lt;span class="rem"&gt;-- Want to add additional information to raiserror, so need to save ErrorID&lt;/span&gt;
    &lt;span class="rem"&gt;-- since next statement clears @@ERROR.&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @ErrorSave &lt;span class="kwrd"&gt;INT&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ErrorSave = 0

  &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 
        UrlId,
        UrlString,
        SqlSchemaName,
        SqlTableName,
        SqlDatabaseName
  &lt;span class="kwrd"&gt;FROM&lt;/span&gt; 
        [WebUrl]
  &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; 
        ([UrlId]= @find_UrlId &lt;span class="kwrd"&gt;OR&lt;/span&gt; @find_UrlId &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; )
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; ([UrlString]= @find_UrlString &lt;span class="kwrd"&gt;OR&lt;/span&gt; @find_UrlString &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; )
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; ([SqlSchemaName]= @find_SqlSchemaName &lt;br /&gt;&lt;span class="kwrd"&gt;OR&lt;/span&gt; (@find_SqlSchemaName &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;))
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; ([SqlTableName]= @find_SqlTableName &lt;br /&gt;&lt;span class="kwrd"&gt;OR&lt;/span&gt; (@find_SqlTableName &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;))
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; ([SqlDatabaseName]= @find_SqlDatabaseName &lt;br /&gt;&lt;span class="kwrd"&gt;OR&lt;/span&gt; (@find_SqlDatabaseName &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;))
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ErrorSave = &lt;span class="preproc"&gt;@@ERROR&lt;/span&gt;

    &lt;span class="kwrd"&gt;IF&lt;/span&gt; @ErrorSave != 0
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
      &lt;span class="kwrd"&gt;RAISERROR&lt;/span&gt;(&lt;span class="str"&gt;'Failure on SELECT for table [WebUrl] in PROCEDURE [SelectUrl].  Error ID=%d.'&lt;/span&gt;, 10, 1, @ErrorSave)
      &lt;span class="kwrd"&gt;RETURN&lt;/span&gt;(@ErrorSave)
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
&lt;span class="kwrd"&gt;END&lt;/span&gt;

&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;So, let’s take a look at the code for this.&amp;#160; I use the ETL acronym (Extract-Transform-Load) as the HtmlTable class suffix as this seems a good description for what we are doing with the web data.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Net;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Common;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; WebEtlHelper
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HtmlTableEtl
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ConnectString { get; set; }
        &lt;span class="kwrd"&gt;private&lt;/span&gt; WebEtlDataClassesDataContext _dc;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; HtmlTableEtl(&lt;span class="kwrd"&gt;string&lt;/span&gt; connectString)
        {
            ConnectString = connectString;
            _dc = &lt;span class="kwrd"&gt;new&lt;/span&gt; WebEtlDataClassesDataContext(connectString); 
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;SelectWebUrlResult&amp;gt; GetUrlInfo (
            &lt;span class="kwrd"&gt;string&lt;/span&gt; dbName, 
            &lt;span class="kwrd"&gt;string&lt;/span&gt; schemaName, 
            &lt;span class="kwrd"&gt;string&lt;/span&gt; tableName)
        {
            List&amp;lt;SelectWebUrlResult&amp;gt; searchResults = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;SelectWebUrlResult&amp;gt;();
            searchResults = _dc.SelectWebUrl(&lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, schemaName, tableName, dbName).ToList&amp;lt;SelectWebUrlResult&amp;gt;();
            &lt;span class="kwrd"&gt;return&lt;/span&gt; searchResults;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;SelectUrlVariableResult&amp;gt; GetUrlVariables (&lt;span class="kwrd"&gt;int&lt;/span&gt; urlId)
        {
            List&amp;lt;SelectUrlVariableResult&amp;gt; searchResults = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;SelectUrlVariableResult&amp;gt;();
            searchResults = _dc.SelectUrlVariable(&lt;span class="kwrd"&gt;false&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, urlId, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;).ToList&amp;lt;SelectUrlVariableResult&amp;gt;();
            &lt;span class="kwrd"&gt;return&lt;/span&gt; searchResults;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;HtmlTable&amp;gt; GetHtmlTables (&lt;span class="kwrd"&gt;int&lt;/span&gt; urlId)
        {
            List&amp;lt;HtmlTable&amp;gt; searchResults = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;HtmlTable&amp;gt;();
            &lt;span class="rem"&gt;// Not using stored procedure for this part, because we want to return&lt;/span&gt;
            &lt;span class="rem"&gt;// the complex data type that includes the child entities&lt;/span&gt;
            &lt;span class="rem"&gt;// Maybe need to use &amp;quot;table type&amp;quot; as part of stored procedure return in SQL?&lt;/span&gt;
            &lt;span class="rem"&gt;// Make sure we are sorting by the table sequence and the column sequence&lt;/span&gt;

            var options = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Data.Linq.DataLoadOptions();
            options.AssociateWith &amp;lt;HtmlTable&amp;gt; (c =&amp;gt; c.HtmlTableColumns.OrderBy (p =&amp;gt; p.ColumnSequence));
            _dc.LoadOptions = options;
            var htmlTables = from p &lt;span class="kwrd"&gt;in&lt;/span&gt; _dc.HtmlTables
                             &lt;span class="kwrd"&gt;where&lt;/span&gt; (p.UrlId == urlId)
                             orderby p.TableSequence
                             select p;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (HtmlTable htmlTable &lt;span class="kwrd"&gt;in&lt;/span&gt; htmlTables)
            {
                searchResults.Add(htmlTable);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; searchResults;
        }

        &lt;span class="rem"&gt;//public List&amp;lt;SelectHtmlTableColumnResult&amp;gt; GetHtmlTableColumns (int htmlTableId)&lt;/span&gt;
        &lt;span class="rem"&gt;//{&lt;/span&gt;
        &lt;span class="rem"&gt;//    List&amp;lt;SelectHtmlTableColumnResult&amp;gt; searchResults = new List&amp;lt;SelectHtmlTableColumnResult&amp;gt;();&lt;/span&gt;
        &lt;span class="rem"&gt;//    using (WebEtlDataClassesDataContext dc = new WebEtlDataClassesDataContext(ConnectString))&lt;/span&gt;
        &lt;span class="rem"&gt;//    {&lt;/span&gt;
        &lt;span class="rem"&gt;//        searchResults = _dc.SelectHtmlTableColumn(null,htmlTableId).ToList&amp;lt;SelectHtmlTableColumnResult&amp;gt;();&lt;/span&gt;
        &lt;span class="rem"&gt;//    }&lt;/span&gt;
        &lt;span class="rem"&gt;//    return searchResults;&lt;/span&gt;
        &lt;span class="rem"&gt;//}&lt;/span&gt;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; String ScrapeWebSite(&lt;span class="kwrd"&gt;string&lt;/span&gt; urlWebQuery)
        {
            WebClient wc = &lt;span class="kwrd"&gt;new&lt;/span&gt; WebClient();
            &lt;span class="kwrd"&gt;string&lt;/span&gt; webData = wc.DownloadString(urlWebQuery);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; webData;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; DataTable GetTableData (&lt;span class="kwrd"&gt;string&lt;/span&gt; webData, HtmlTable htmlTable)
        {
            DataTable dt = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataTable();
            &lt;span class="rem"&gt;// At this point, we now have the downloaded web data along with the list of columns &lt;/span&gt;
            &lt;span class="rem"&gt;// and the information needed to search for the columns&lt;/span&gt;
            &lt;span class="rem"&gt;// First, get rid of special characters including carriage return, tabs, linefeeds&lt;/span&gt;
            webData = webData.Replace(&lt;span class="str"&gt;&amp;quot;\r&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
            webData = webData.Replace(&lt;span class="str"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
            webData = webData.Replace(&lt;span class="str"&gt;&amp;quot;\t&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
            &lt;span class="rem"&gt;// Assume we are dealing with non-case sensitive data, so we upper-case everything to make it simpler.&lt;/span&gt;
            webData = webData.ToUpper();
        
            &lt;span class="kwrd"&gt;int&lt;/span&gt; tableStart = webData.IndexOf(htmlTable.TableStartString.ToUpper());
            tableStart = tableStart + htmlTable.TableStartString.Length;
            &lt;span class="kwrd"&gt;string&lt;/span&gt; tableData = webData.Substring(tableStart);
            &lt;span class="kwrd"&gt;int&lt;/span&gt; tableEnd = tableData.IndexOf(htmlTable.TableEndString.ToUpper());
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (tableEnd &amp;gt; 0)
                &lt;span class="rem"&gt;// We have something to parse&lt;/span&gt;
            {
                tableData = tableData.Substring
                    (0,tableEnd);
                &lt;span class="rem"&gt;// Now comes the hard part&lt;/span&gt;
                dt = parseTable(tableData, htmlTable.HtmlTableColumns.ToList&amp;lt;HtmlTableColumn&amp;gt;());
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; dt;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; DataTable parseTable(&lt;span class="kwrd"&gt;string&lt;/span&gt; tableData, List&amp;lt;HtmlTableColumn&amp;gt; htmlTableColumns)
        {
            DataTable dt = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataTable();
            &lt;span class="rem"&gt;// To get here, we must have something that shold be parsable and there are no carriage returns&lt;/span&gt;
            &lt;span class="rem"&gt;// We need to split each cell within each row to get the data.&lt;/span&gt;
            &lt;span class="rem"&gt;// First lets split the rows, we do this by converting the table data &amp;lt;/TR&amp;gt; to carriage returns&lt;/span&gt;
            &lt;span class="rem"&gt;// The whole string has already been upper-cased at this point.&lt;/span&gt;
            tableData = tableData.ToUpper().Replace(&lt;span class="str"&gt;@&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
            tableData = tableData.Replace(&lt;span class="str"&gt;@&amp;quot;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;);
            tableData = tableData.Replace(&lt;span class="str"&gt;@&amp;quot;&amp;lt;TD&amp;gt;&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
            tableData = tableData.Replace(&lt;span class="str"&gt;@&amp;quot;&amp;lt;/TD&amp;gt;&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;\t&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;string&lt;/span&gt;[] rows = tableData.Split(&lt;span class="str"&gt;'\n'&lt;/span&gt;);
            &lt;span class="rem"&gt;// split to colums&lt;/span&gt;
            &lt;span class="rem"&gt;// add the columns to the DataTable&lt;/span&gt;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (HtmlTableColumn htc &lt;span class="kwrd"&gt;in&lt;/span&gt; htmlTableColumns)
                dt.Columns.Add(htc.SqlColumnName);
            DataRow row = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;string&lt;/span&gt;[] rowValues;
            &lt;span class="kwrd"&gt;object&lt;/span&gt;[] rowItems;
            &lt;span class="rem"&gt;// split the rows&lt;/span&gt;
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; rows.Length; i++)
            {
                rowValues = rows[i].Split(&lt;span class="str"&gt;'\t'&lt;/span&gt;);
                row = dt.NewRow();
                rowItems = Utility.ConvertStringArrayToObjectArray(rowValues);
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (rowItems[0] != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; (&lt;span class="kwrd"&gt;string&lt;/span&gt;)rowItems[0] != &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
                {
                    row.ItemArray = rowItems;
                    dt.Rows.Add(row);
                }
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; dt;
        }



        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SetUrlQueryStringValues (&lt;span class="kwrd"&gt;string&lt;/span&gt; urlString, List&amp;lt;QueryVariable&amp;gt; queryVariables)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; newUrlString = urlString;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (QueryVariable qv &lt;span class="kwrd"&gt;in&lt;/span&gt; queryVariables)
            {
                newUrlString = newUrlString.Replace(qv.VariableName, qv.VariableValue);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; newUrlString;
        }
    }
}&lt;/font&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;To go over how to use this, let’s look at the code for our sample application and see how the various methods are leveraged.&amp;#160;&amp;#160; The following is a summary of steps:&lt;/p&gt;

&lt;p&gt;Define the instance-level variables that are shared between our setup logic and the actual parsing.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Instantiate the class &lt;/li&gt;

  &lt;li&gt;Get the URL Metadata including query parameter replacement variables from Database based on the database/schema/table name we wish to load. &lt;/li&gt;

  &lt;li&gt;Get the HTML Table definitions and column lists associated with the URL &lt;/li&gt;

  &lt;li&gt;Setup the URL Variables table to enable the variable replacement in the query string.&lt;/li&gt;
&lt;/ol&gt;

&lt;div align="left"&gt;
  &lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;First, we create our instance-level variables for storing the metadata&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div align="left"&gt;
  &lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; List&amp;lt;HtmlTable&amp;gt; _htmlTables;
        &lt;span class="rem"&gt;// Contains list of all the tables for the HTML along with&lt;/span&gt;
        &lt;span class="rem"&gt;// a child relation for the columns.  This is the metadata&lt;/span&gt;
        &lt;span class="rem"&gt;// that enables parsing the data.&lt;/span&gt;

        List&amp;lt;SelectUrlVariableResult&amp;gt; _variableResults;
        &lt;span class="rem"&gt;// This is the list of query variables applicable&lt;/span&gt;
        &lt;span class="rem"&gt;// to this URL.&lt;/span&gt;

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _urlTemplateString;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; setupDownloadTables()
        {
            &lt;span class="rem"&gt;// Setup Logging&lt;/span&gt;
            TextWriterTraceListener myWriter = &lt;span class="kwrd"&gt;new&lt;/span&gt;
            TextWriterTraceListener(
                System.IO.File.CreateText(&lt;span class="str"&gt;&amp;quot;Msn10YearDownloader_&amp;quot;&lt;/span&gt;
                + Common.Utility.BuildFileDateTimeStamp() + &lt;span class="str"&gt;&amp;quot;.log&amp;quot;&lt;/span&gt;));
            Trace.Listeners.Add(myWriter);

Next, instantiate the HtmlTableEtl class&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div align="left"&gt;
  &lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;            &lt;span class="rem"&gt;// Instantiate the Html Table Extract-Transform-Load (ETL) helper HtmlTableEtl&lt;/span&gt;
            WebEtlHelper.HtmlTableEtl etl = &lt;span class="kwrd"&gt;new&lt;/span&gt; HtmlTableEtl
                (Properties.Settings.Default.TradingOptimizer_v3ConnectionString);
            
Get the URL info from the database by passing in the &lt;br /&gt;desired database, schema, and table name.&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div align="left"&gt;
  &lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;            &lt;span class="rem"&gt;// Get the Url Info &lt;/span&gt;
            List&amp;lt;WebEtlHelper.SelectWebUrlResult&amp;gt; urlResults
                = etl.GetUrlInfo(&lt;span class="str"&gt;&amp;quot;TradingOptimizer_v3&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;load&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Msn10YearSummary&amp;quot;&lt;/span&gt;);
            &lt;span class="rem"&gt;// Should only be one&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div align="left"&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;&lt;/span&gt;&lt;font face="Arial Narrow"&gt;For our scenario, we only have 1 URL, but we could handle multiple URLs
&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div align="left"&gt;
  &lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (SelectWebUrlResult urlResult &lt;span class="kwrd"&gt;in&lt;/span&gt; urlResults)
            {
                _urlTemplateString = urlResult.UrlString;
                &lt;span class="rem"&gt;// Setup empty data tables, do this now as a design pattern for batch processing, &lt;/span&gt;
                &lt;span class="rem"&gt;// rather than embedding in the data loop.  The metadata should only need to be&lt;/span&gt;
                &lt;span class="rem"&gt;// accessed at the beginning of processing.&lt;/span&gt;
                &lt;span class="rem"&gt;// The list of htmlTables should automatically contain the list of columns as&lt;/span&gt;
                &lt;/font&gt;&lt;span class="rem"&gt;&lt;font face="Arial Narrow"&gt;// well.&lt;br /&gt;&lt;br /&gt;&lt;font color="#000000"&gt;Next, we populate the HTML Table definitions based on the URL ID &lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div align="left"&gt;
  &lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;&lt;span class="rem"&gt;&lt;font color="#000000"&gt;This will populate a table containing the HTML table structure&lt;br /&gt;as well as the columns that need to be mapped to the database.&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;                _htmlTables =
                    etl.GetHtmlTables(urlResult.UrlId);
                &lt;/font&gt;&lt;font face="Arial Narrow"&gt;&lt;span class="rem"&gt;// Get the variables for the query string (should just be the trading symbol)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#000000"&gt;_variableResults should now contain the list of query parameters that need to be replaced&lt;/font&gt;&lt;br /&gt;&lt;/span&gt;
                _variableResults = etl.GetUrlVariables(urlResult.UrlId);
                &lt;span class="rem"&gt;// Now all the plumbing should be in place&lt;/span&gt;
            }
        }&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p align="left"&gt;Now, that we have the metadata in place, we can use the parsing aspect of the component.&amp;#160; Hopefully, the comments in the code are self-explanatory.&amp;#160; Basically, the processing consisting of the following steps&lt;/p&gt;

&lt;div align="left"&gt;
  &lt;ol&gt;
    &lt;li&gt;Update query variable with passed in value (tradingSymbol) &lt;/li&gt;

    &lt;li&gt;Download the web data using the query string &lt;/li&gt;

    &lt;li&gt;Call the ScrapeWebSite method from the HtmlTableEtl class passing in the HtmlTable metadata and the web data. &lt;/li&gt;

    &lt;li&gt;Iterate through the tables returned from the ScrapeWebSite calls (store them in a list) and set the values to the Linq Entity based on the column mapping.&amp;#160; Note, that at this point, we have hard-wired the names to look for, but this could be done generically by generating a dynamic SQL statement. &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;

&lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; insertMsn10YearSummary(&lt;span class="kwrd"&gt;string&lt;/span&gt; tradingSymbol)
        {
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                List&amp;lt;DataTable&amp;gt; dts = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;DataTable&amp;gt;();

                &lt;span class="kwrd"&gt;string&lt;/span&gt; urlString = _urlTemplateString;
                &lt;span class="rem"&gt;// Get the variables for the query string (should just be the trading symbol)&lt;/span&gt;
                List&amp;lt;QueryVariable&amp;gt; queryVariables = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;QueryVariable&amp;gt;();
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (SelectUrlVariableResult variable &lt;span class="kwrd"&gt;in&lt;/span&gt; _variableResults)
                {
                    queryVariables.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; QueryVariable(variable.UrlVariableName, tradingSymbol));
                }

                &lt;span class="rem"&gt;// Update the query string&lt;/span&gt;
                urlString = HtmlTableEtl.SetUrlQueryStringValues(urlString, queryVariables);
                &lt;span class="rem"&gt;// Run the query to get the data, the infrastructure should be in place to &lt;/span&gt;
                &lt;span class="rem"&gt;// populate the data.&lt;/span&gt;
                &lt;span class="kwrd"&gt;string&lt;/span&gt; webData = HtmlTableEtl.ScrapeWebSite(urlString);
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (HtmlTable htmlTable &lt;span class="kwrd"&gt;in&lt;/span&gt; _htmlTables)
                {
                    DataTable dt = HtmlTableEtl.GetTableData(
                        webData,
                        htmlTable);
                    dts.Add(dt);
                }

                &lt;span class="rem"&gt;// Insert the rows into our target table by mapping back to the data table.&lt;/span&gt;
                &lt;span class="rem"&gt;// We are &amp;quot;weak-typed&amp;quot; at this point, not sure best way to make this a &lt;/span&gt;
                &lt;span class="rem"&gt;// more strongly-typed approach without compromising on the genericity&lt;/span&gt;
                &lt;span class="rem"&gt;// It would be easy enough to use a table adapter and generate a generic SQL&lt;/span&gt;
                &lt;span class="rem"&gt;// insert instead of referencing each column.&lt;/span&gt;

                &lt;span class="kwrd"&gt;using&lt;/span&gt; (MsnDownloadDataClassesDataContext dc = &lt;span class="kwrd"&gt;new&lt;/span&gt; MsnDownloadDataClassesDataContext())
                {
                    &lt;span class="rem"&gt;// For this scenario, we already know that there are only 2 tables with the same &lt;/span&gt;
                    &lt;span class="rem"&gt;// number of rows, so we just iterate the first table and then pull from the second&lt;/span&gt;
                    &lt;span class="rem"&gt;// to build the row to insert&lt;/span&gt;
                    &lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0;
                    List&amp;lt;Msn10YearSummary&amp;gt; msnRows = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Msn10YearSummary&amp;gt;();
                    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (DataRow dr &lt;span class="kwrd"&gt;in&lt;/span&gt; dts[0].Rows)
                    {
                        Msn10YearSummary msnRow = &lt;span class="kwrd"&gt;new&lt;/span&gt; Msn10YearSummary();
                        msnRow.TradingSymbol = tradingSymbol;
                        &lt;span class="rem"&gt;// Add 2 months to effective date since it can take 60 days for a company to &lt;/span&gt;
                        &lt;span class="rem"&gt;// announce earnings.&lt;/span&gt;
                        msnRow.EffectiveDate =
                            Utility.ConvertMmYytoDate(dr[&lt;span class="str"&gt;&amp;quot;EffectiveDate&amp;quot;&lt;/span&gt;].ToString(), 90).Value.AddMonths(2);
                        msnRow.AvgPe = Utility.ConvertDecimal(dr[&lt;span class="str"&gt;&amp;quot;AvgPe&amp;quot;&lt;/span&gt;]);
                        msnRow.PriceSales = Utility.ConvertDecimal(dr[&lt;span class="str"&gt;&amp;quot;PriceSales&amp;quot;&lt;/span&gt;]);
                        msnRow.PriceBook = Utility.ConvertDecimal(dr[&lt;span class="str"&gt;&amp;quot;PriceBook&amp;quot;&lt;/span&gt;]);
                        msnRow.NetProfitMarginPct = Utility.ConvertDecimal(dr[&lt;span class="str"&gt;&amp;quot;NetProfitMarginPct&amp;quot;&lt;/span&gt;]);

                        &lt;span class="rem"&gt;// Next set of fields are in the second table.&lt;/span&gt;
                        DataRow dr2 = dts[1].Rows[i];
                        msnRow.BookValueShare = Utility.ConvertDecimal(dr2[&lt;span class="str"&gt;&amp;quot;BookValueShare&amp;quot;&lt;/span&gt;]);
                        msnRow.DebtEquity = Utility.ConvertDecimal(dr2[&lt;span class="str"&gt;&amp;quot;DebtEquity&amp;quot;&lt;/span&gt;]);
                        msnRow.ReturnOnEquityPct = Utility.ConvertDecimal(dr2[&lt;span class="str"&gt;&amp;quot;ReturnOnEquityPct&amp;quot;&lt;/span&gt;]);
                        msnRow.ReturnOnAssetsPct = Utility.ConvertDecimal(dr2[&lt;span class="str"&gt;&amp;quot;ReturnOnAssetsPct&amp;quot;&lt;/span&gt;]);
                        msnRow.InterestCoverage = Utility.ConvertDecimal(dr2[&lt;span class="str"&gt;&amp;quot;InterestCoverage&amp;quot;&lt;/span&gt;]);
                        msnRows.Add(msnRow);
                        i++;
                    }
                    dc.Msn10YearSummaries.InsertAllOnSubmit(msnRows);
                    dc.SubmitChanges();
                }
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                Trace.WriteLine(Utility.buildExceptionMessage(&lt;span class="str"&gt;&amp;quot;Error downloading info for &amp;quot;&lt;/span&gt; + tradingSymbol + &lt;span class="str"&gt;&amp;quot;; &amp;quot;&lt;/span&gt;, ex));
            }
        }&lt;/font&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;There are a couple of references to some utility functions that I’ve included below.&amp;#160; These help deal with the conversion aspects of the data.&amp;#160; Just because we can hit the URL, doesn’t mean that there is actually valid data, in some cases, some of the fields are missing depending on the equity.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;font face="Arial Narrow"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;decimal&lt;/span&gt;? ConvertDecimal(&lt;span class="kwrd"&gt;string&lt;/span&gt; decimalString)
        {
            &lt;span class="kwrd"&gt;decimal&lt;/span&gt;? decimalVal = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;decimal&lt;/span&gt;();
            decimalVal = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (decimalString != &lt;span class="str"&gt;&amp;quot;N/A&amp;quot;&lt;/span&gt;)
            {
                &lt;span class="rem"&gt;// Get rid of &amp;quot;$&amp;quot;&lt;/span&gt;
                &lt;span class="kwrd"&gt;try&lt;/span&gt; { decimalVal = Convert.ToDecimal(decimalString.Replace(&lt;span class="str"&gt;&amp;quot;$&amp;quot;&lt;/span&gt;,&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)); }
                &lt;span class="kwrd"&gt;catch&lt;/span&gt; { }
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; decimalVal;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;decimal&lt;/span&gt;? ConvertDecimal(&lt;span class="kwrd"&gt;object&lt;/span&gt; decimalObject)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; ConvertDecimal(decimalObject.ToString());
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Int64? ConvertInt64(&lt;span class="kwrd"&gt;string&lt;/span&gt; int64String)
        {
            Int64? int64Val = &lt;span class="kwrd"&gt;new&lt;/span&gt; Int64();
            int64Val = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (int64String != &lt;span class="str"&gt;&amp;quot;N/A&amp;quot;&lt;/span&gt;)
            {
                &lt;span class="rem"&gt;// eliminate the decimal point&lt;/span&gt;
                &lt;span class="rem"&gt;// if it ends with &amp;quot;B&amp;quot;, then multiply by 1,000,000,000&lt;/span&gt;
                &lt;span class="rem"&gt;// if it ends with M then multiply by 1,000,000&lt;/span&gt;
                &lt;span class="rem"&gt;// if it ends with K then multiply by 1,000&lt;/span&gt;
                &lt;span class="rem"&gt;// Detect the unit of measurement&lt;/span&gt;
                &lt;span class="kwrd"&gt;decimal&lt;/span&gt; factor = 1;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (int64String.EndsWith(&lt;span class="str"&gt;&amp;quot;B&amp;quot;&lt;/span&gt;))
                {
                    factor = 1000000000;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (int64String.EndsWith(&lt;span class="str"&gt;&amp;quot;M&amp;quot;&lt;/span&gt;))
                {
                    factor = 1000000;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (int64String.EndsWith(&lt;span class="str"&gt;&amp;quot;K&amp;quot;&lt;/span&gt;))
                {
                    factor = 1000;
                }
                &lt;span class="kwrd"&gt;string&lt;/span&gt; multiplierString = int64String.Replace(&lt;span class="str"&gt;&amp;quot;B&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;000000000&amp;quot;&lt;/span&gt;);
                multiplierString = multiplierString.Replace(&lt;span class="str"&gt;&amp;quot;M&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;000000&amp;quot;&lt;/span&gt;);
                multiplierString = multiplierString.Replace(&lt;span class="str"&gt;&amp;quot;K&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;000&amp;quot;&lt;/span&gt;);

                &lt;span class="kwrd"&gt;try&lt;/span&gt;
                {
                    int64Val = (Convert.ToInt64(Convert.ToDecimal&lt;br /&gt;(multiplierString) * Convert.ToDecimal(factor)));
                }
                &lt;span class="kwrd"&gt;catch&lt;/span&gt; { }
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; int64Val;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; DateTime? ConvertMmYytoDate(&lt;span class="kwrd"&gt;string&lt;/span&gt; mmyy, &lt;span class="kwrd"&gt;int&lt;/span&gt; maxMillenniumYear)
        {
            &lt;span class="rem"&gt;// Returns a date extrapolated from a mm/yy string. Sets day to first of month&lt;/span&gt;
            &lt;span class="rem"&gt;// maxMillenniumYear is the furtherest year in the future to assume as being&lt;/span&gt;
            &lt;span class="rem"&gt;// in the 20th millennium.  I.e., if 20 passed and yymm is 03/21 then return &lt;/span&gt;
            &lt;span class="rem"&gt;// date of 03/01/1921.  If 20 passed and yymm is 03/20 then return 03/01/2020.&lt;/span&gt;
            DateTime? convertDate = &lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime();
            &lt;span class="rem"&gt;// Assumes 2 digit years and leading 0s are included in the month&lt;/span&gt;
            &lt;span class="rem"&gt;// null is returned if date couldn't be parsed.&lt;/span&gt;
            &lt;span class="rem"&gt;// if parse failure occurs, an exception is raised and must be &lt;/span&gt;
            &lt;span class="rem"&gt;// handled by calling routine&lt;/span&gt;
            mmyy = mmyy.Replace(&lt;span class="str"&gt;@&amp;quot;/&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (mmyy.Length == 4)
            {
                &lt;span class="kwrd"&gt;int&lt;/span&gt; yyyy = Convert.ToInt16(mmyy.Substring(2, 2));
                yyyy = (yyyy &amp;gt; maxMillenniumYear) ? yyyy + 1900 : 2000 + yyyy;
                &lt;span class="kwrd"&gt;int&lt;/span&gt; mm = Convert.ToInt16(mmyy.Substring(0, 2));
                convertDate = Convert.ToDateTime(mm.ToString() + &lt;span class="str"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; + &lt;span class="str"&gt;&amp;quot;01&amp;quot;&lt;/span&gt; + &lt;br /&gt;&lt;span class="str"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; + yyyy.ToString());
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; convertDate;
        }&lt;/font&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;This is all called through a simple Windows Form App with a button that runs a function to iterate through our LINQ source data source containing all of the equities we want to process.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Dataminingthewebforfunandprofit_81BC/image_6.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Dataminingthewebforfunandprofit_81BC/image_thumb_2.png" width="244" height="240" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The download all button runs the below code to invoke the &lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; buttonDownloadAll_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            setupDownloadTables();
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (MsnDownloadDataClassesDataContext dc = &lt;br /&gt;&lt;span class="kwrd"&gt;new&lt;/span&gt; MsnDownloadDataClassesDataContext())
            {
                var symbols = from p &lt;span class="kwrd"&gt;in&lt;/span&gt; dc.EquitySymbols
                              &lt;span class="kwrd"&gt;where&lt;/span&gt; (p.Tradeable.Value == &lt;span class="kwrd"&gt;true&lt;/span&gt;)
                              select p;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (EquitySymbol es &lt;span class="kwrd"&gt;in&lt;/span&gt; symbols)
                {
                    insertMsn10YearSummary(es.TradingSymbol);
                }
            }
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;To show you that this really works, here’s the first 50 rows from our downloaded table for the columns defined in the first HTML Table.&amp;#160; As I mentioned earlier, not all of the data is available for all of of the equities, hence the nulls in some of the columns.&amp;#160; Note that I push the effective date out 2 months from what is reported on the web because it can take that long for companies to report earnings and my simulation correlation analysis has to operate in the context of the reality of what was known at the time of the simulation.&amp;#160; Also, the EndDate is a computed column based on adding 1 year and subtracting 1 day, that gives us our nice range intervals ((dateadd(day,(-1),dateadd(year,(1),[EffectiveDate])))&lt;/p&gt;

&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="64"&gt;TradingSymbol&lt;/td&gt;

      &lt;td width="92"&gt;EffectiveDate&lt;/td&gt;

      &lt;td width="75"&gt;EndDate&lt;/td&gt;

      &lt;td width="64"&gt;AvgPe&lt;/td&gt;

      &lt;td width="64"&gt;PriceSales&lt;/td&gt;

      &lt;td width="64"&gt;PriceBook&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/1999&lt;/td&gt;

      &lt;td&gt;11/30/2000&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2000&lt;/td&gt;

      &lt;td&gt;11/30/2001&lt;/td&gt;

      &lt;td&gt;44.9&lt;/td&gt;

      &lt;td&gt;2.12&lt;/td&gt;

      &lt;td&gt;3.77&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2001&lt;/td&gt;

      &lt;td&gt;11/30/2002&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;1.15&lt;/td&gt;

      &lt;td&gt;1.71&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2002&lt;/td&gt;

      &lt;td&gt;11/30/2003&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;1.31&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2003&lt;/td&gt;

      &lt;td&gt;11/30/2004&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;2.49&lt;/td&gt;

      &lt;td&gt;3.96&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2004&lt;/td&gt;

      &lt;td&gt;11/30/2005&lt;/td&gt;

      &lt;td&gt;216&lt;/td&gt;

      &lt;td&gt;2.54&lt;/td&gt;

      &lt;td&gt;3.23&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2005&lt;/td&gt;

      &lt;td&gt;11/30/2006&lt;/td&gt;

      &lt;td&gt;62.2&lt;/td&gt;

      &lt;td&gt;3.22&lt;/td&gt;

      &lt;td&gt;3.72&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2006&lt;/td&gt;

      &lt;td&gt;11/30/2007&lt;/td&gt;

      &lt;td&gt;9.8&lt;/td&gt;

      &lt;td&gt;2.98&lt;/td&gt;

      &lt;td&gt;3.76&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2007&lt;/td&gt;

      &lt;td&gt;11/30/2008&lt;/td&gt;

      &lt;td&gt;22.5&lt;/td&gt;

      &lt;td&gt;2.76&lt;/td&gt;

      &lt;td&gt;4.22&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;

      &lt;td&gt;12/1/2008&lt;/td&gt;

      &lt;td&gt;11/30/2009&lt;/td&gt;

      &lt;td&gt;17.7&lt;/td&gt;

      &lt;td&gt;1.43&lt;/td&gt;

      &lt;td&gt;3.03&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2000&lt;/td&gt;

      &lt;td&gt;1/31/2001&lt;/td&gt;

      &lt;td&gt;20.6&lt;/td&gt;

      &lt;td&gt;1.9&lt;/td&gt;

      &lt;td&gt;4.83&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2001&lt;/td&gt;

      &lt;td&gt;1/31/2002&lt;/td&gt;

      &lt;td&gt;17.7&lt;/td&gt;

      &lt;td&gt;1.22&lt;/td&gt;

      &lt;td&gt;2.54&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2002&lt;/td&gt;

      &lt;td&gt;1/31/2003&lt;/td&gt;

      &lt;td&gt;35.5&lt;/td&gt;

      &lt;td&gt;1.36&lt;/td&gt;

      &lt;td&gt;2.84&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2003&lt;/td&gt;

      &lt;td&gt;1/31/2004&lt;/td&gt;

      &lt;td&gt;49.2&lt;/td&gt;

      &lt;td&gt;0.97&lt;/td&gt;

      &lt;td&gt;1.94&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2004&lt;/td&gt;

      &lt;td&gt;1/31/2005&lt;/td&gt;

      &lt;td&gt;21.7&lt;/td&gt;

      &lt;td&gt;1.56&lt;/td&gt;

      &lt;td&gt;2.73&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2005&lt;/td&gt;

      &lt;td&gt;1/31/2006&lt;/td&gt;

      &lt;td&gt;21.2&lt;/td&gt;

      &lt;td&gt;1.22&lt;/td&gt;

      &lt;td&gt;2.06&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2006&lt;/td&gt;

      &lt;td&gt;1/31/2007&lt;/td&gt;

      &lt;td&gt;19.6&lt;/td&gt;

      &lt;td&gt;1.01&lt;/td&gt;

      &lt;td&gt;1.92&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2007&lt;/td&gt;

      &lt;td&gt;1/31/2008&lt;/td&gt;

      &lt;td&gt;11.9&lt;/td&gt;

      &lt;td&gt;0.91&lt;/td&gt;

      &lt;td&gt;1.78&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2008&lt;/td&gt;

      &lt;td&gt;1/31/2009&lt;/td&gt;

      &lt;td&gt;11.3&lt;/td&gt;

      &lt;td&gt;1.08&lt;/td&gt;

      &lt;td&gt;1.89&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA&lt;/td&gt;

      &lt;td&gt;2/1/2009&lt;/td&gt;

      &lt;td&gt;1/31/2010&lt;/td&gt;

      &lt;td&gt;103.2&lt;/td&gt;

      &lt;td&gt;0.34&lt;/td&gt;

      &lt;td&gt;0.77&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AA.P&lt;/td&gt;

      &lt;td&gt;0001-03-01&lt;/td&gt;

      &lt;td&gt;0002-02-28&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2000&lt;/td&gt;

      &lt;td&gt;1/31/2001&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;71.73&lt;/td&gt;

      &lt;td&gt;36.85&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2001&lt;/td&gt;

      &lt;td&gt;1/31/2002&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;6.66&lt;/td&gt;

      &lt;td&gt;19.3&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2002&lt;/td&gt;

      &lt;td&gt;1/31/2003&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;7.37&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2003&lt;/td&gt;

      &lt;td&gt;1/31/2004&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;2.99&lt;/td&gt;

      &lt;td&gt;3.58&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2004&lt;/td&gt;

      &lt;td&gt;1/31/2005&lt;/td&gt;

      &lt;td&gt;1997.5&lt;/td&gt;

      &lt;td&gt;41.94&lt;/td&gt;

      &lt;td&gt;6.42&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2005&lt;/td&gt;

      &lt;td&gt;1/31/2006&lt;/td&gt;

      &lt;td&gt;68.9&lt;/td&gt;

      &lt;td&gt;10.45&lt;/td&gt;

      &lt;td&gt;4.42&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2006&lt;/td&gt;

      &lt;td&gt;1/31/2007&lt;/td&gt;

      &lt;td&gt;67.7&lt;/td&gt;

      &lt;td&gt;4.36&lt;/td&gt;

      &lt;td&gt;1.51&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2007&lt;/td&gt;

      &lt;td&gt;1/31/2008&lt;/td&gt;

      &lt;td&gt;115.7&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;

      &lt;td&gt;0.97&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2008&lt;/td&gt;

      &lt;td&gt;1/31/2009&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;1.69&lt;/td&gt;

      &lt;td&gt;0.58&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAC&lt;/td&gt;

      &lt;td&gt;2/1/2009&lt;/td&gt;

      &lt;td&gt;1/31/2010&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;0.51&lt;/td&gt;

      &lt;td&gt;0.17&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2000&lt;/td&gt;

      &lt;td&gt;1/31/2001&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2001&lt;/td&gt;

      &lt;td&gt;1/31/2002&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2002&lt;/td&gt;

      &lt;td&gt;1/31/2003&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2003&lt;/td&gt;

      &lt;td&gt;1/31/2004&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2004&lt;/td&gt;

      &lt;td&gt;1/31/2005&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2005&lt;/td&gt;

      &lt;td&gt;1/31/2006&lt;/td&gt;

      &lt;td&gt;893.8&lt;/td&gt;

      &lt;td&gt;3.61&lt;/td&gt;

      &lt;td&gt;4.02&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2006&lt;/td&gt;

      &lt;td&gt;1/31/2007&lt;/td&gt;

      &lt;td&gt;17&lt;/td&gt;

      &lt;td&gt;3.31&lt;/td&gt;

      &lt;td&gt;3.35&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2007&lt;/td&gt;

      &lt;td&gt;1/31/2008&lt;/td&gt;

      &lt;td&gt;14.7&lt;/td&gt;

      &lt;td&gt;2.42&lt;/td&gt;

      &lt;td&gt;2.28&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2008&lt;/td&gt;

      &lt;td&gt;1/31/2009&lt;/td&gt;

      &lt;td&gt;22.5&lt;/td&gt;

      &lt;td&gt;1.37&lt;/td&gt;

      &lt;td&gt;2.6&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AACC&lt;/td&gt;

      &lt;td&gt;2/1/2009&lt;/td&gt;

      &lt;td&gt;1/31/2010&lt;/td&gt;

      &lt;td&gt;19.5&lt;/td&gt;

      &lt;td&gt;0.67&lt;/td&gt;

      &lt;td&gt;1.14&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2000&lt;/td&gt;

      &lt;td&gt;1/31/2001&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;0.56&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2001&lt;/td&gt;

      &lt;td&gt;1/31/2002&lt;/td&gt;

      &lt;td&gt;6.7&lt;/td&gt;

      &lt;td&gt;0.8&lt;/td&gt;

      &lt;td&gt;60.71&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2002&lt;/td&gt;

      &lt;td&gt;1/31/2003&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;0.67&lt;/td&gt;

      &lt;td&gt;13.74&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2003&lt;/td&gt;

      &lt;td&gt;1/31/2004&lt;/td&gt;

      &lt;td&gt;33.7&lt;/td&gt;

      &lt;td&gt;0.39&lt;/td&gt;

      &lt;td&gt;5.35&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2004&lt;/td&gt;

      &lt;td&gt;1/31/2005&lt;/td&gt;

      &lt;td&gt;8.7&lt;/td&gt;

      &lt;td&gt;1.12&lt;/td&gt;

      &lt;td&gt;3.32&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2005&lt;/td&gt;

      &lt;td&gt;1/31/2006&lt;/td&gt;

      &lt;td&gt;150&lt;/td&gt;

      &lt;td&gt;0.92&lt;/td&gt;

      &lt;td&gt;2.79&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2006&lt;/td&gt;

      &lt;td&gt;1/31/2007&lt;/td&gt;

      &lt;td&gt;129.5&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;

      &lt;td&gt;4.03&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2007&lt;/td&gt;

      &lt;td&gt;1/31/2008&lt;/td&gt;

      &lt;td&gt;84.6&lt;/td&gt;

      &lt;td&gt;0.57&lt;/td&gt;

      &lt;td&gt;2.82&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;AAI&lt;/td&gt;

      &lt;td&gt;2/1/2008&lt;/td&gt;

      &lt;td&gt;1/31/2009&lt;/td&gt;

      &lt;td&gt;18.8&lt;/td&gt;

      &lt;td&gt;0.32&lt;/td&gt;

      &lt;td&gt;1.47&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:355143b1-12d9-41de-88ad-cbbc1dfe82a2" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Code+Project" rel="tag"&gt;Code Project&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Data+Mining" rel="tag"&gt;Data Mining&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Web+Data+Mining" rel="tag"&gt;Web Data Mining&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9882966" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/CodeProject/default.aspx">CodeProject</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Simulation/default.aspx">Simulation</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Visual+Studio.NET/default.aspx">Visual Studio.NET</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Data+Mining/default.aspx">Data Mining</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Web+Data+Mining/default.aspx">Web Data Mining</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Web+Scraping/default.aspx">Web Scraping</category></item><item><title>Nested Identity Keys in SQL?</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/24/nested-identity-keys-in-sql.aspx</link><pubDate>Mon, 24 Aug 2009 18:32:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9882744</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9882744.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9882744</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9882744</wfw:comment><description>&lt;p&gt;This weekend I played with partitioning.&amp;#160; I have a table with about 10 million rows spanning the last 6 years of stock history for AMEX, NYSE, Indexes, and NASDAQ.&amp;#160;&amp;#160; I partitioned each year into a separate filegroup so that should make it much easier to purge archive the old years and try to speed up queries on date ranges that involved multiple tables by storage-aligning the indexes.&amp;#160; I aligned a related table used for storing calculations and metrics along with aligning an indexed view. Although a few queries actually ran slower, the most critical ones ran faster with the partitioning, since I typically retrieve data grouped together in a fairly tight range.&lt;/p&gt;  &lt;p&gt;It seems that in order to really get storage alignment to work well with partitioned tables, you may want to move away from simple surrogate primary keys to compound primary keys where one segment is the partitioning key and the other segment is the unique key. One of the requirements for a partitioning a table is that the partitioning column be part of the clustered key, so unless you are partitioning on what is already the primary clustered key, you’re looking at either no longer using the primary key as the clustering key or creating a compound key. And until recently, the advice has typically been to use simple surrogate&amp;#160; primary clustered keys for best performance, which means you would not typically want to partition on an existing surrogate key when moving to partitioning, since by definition a surrogate key generally has no significance, and thus typically not a relevant partitioning parameter.&lt;/p&gt;  &lt;p&gt;Therefore partitioning introduces some new dynamics in the way one designs primary keys.&lt;/p&gt;  &lt;p&gt;What would be helpful would be to create an identity column grouped on another column (nested). Say I have a partitioning key of year, then I could have my order Id be reset for each year. The advantage is that the overall index space can be reduced since the numbers are only unique within a range for each of the partitioning keys, allowing a smaller data type to be used for the nested identity key.&amp;#160; &lt;/p&gt;  &lt;p&gt;For example, if I have over 2^32 billion rows (or about 4.2 billion rows), I would have to use a bigint for a surrogate primary key, even if using the negative range (which is unlikely, so the real limit is more like 2.1 billion).&amp;#160; If I create 20 partitions, I can now go to 80 billion rows using a simple surrogate integer plus a tinyint partitioning key, assuming non-negative identity values.&amp;#160; This means that using the partitioning scheme, I actually use only 5 bytes per unique index value, rather than 8 bytes, and am able to accommodate up to 255 times more data than if using the simple 4 byte key alone.&lt;/p&gt;  &lt;p&gt;The other scenario is where you commonly need to keep items in a static order within a parent, i.e. a bill of materials assembly where the line number represents the sequence in which an assembly is to be constructed.&amp;#160; To be able to automatically generate sequence numbers guaranteed to be unique within the context of a parent assembly number would be useful.&lt;/p&gt;  &lt;p&gt;This could be done with a trigger of course, but that’s not real efficient, and presents more challenges in bulk-loading scenarios.&lt;/p&gt;  &lt;p&gt;What I’m thinking of is some syntax along the lines of &lt;/p&gt;  &lt;p&gt;CREATE TABLE Table-name &lt;/p&gt;  &lt;p&gt;(Grouping-key datatype,&lt;/p&gt;  &lt;p&gt;Grouped-Identity-Key datatype identity [start,increment] &lt;font color="#ff0000"&gt;group by PartitioningId&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;And then you just partition on the Grouping-key for the primary key on a partitioning scheme as in:&lt;/p&gt;  &lt;p&gt;ALTER TABLE Table-name&lt;/p&gt;  &lt;p&gt;ADD&lt;/p&gt;  &lt;p&gt;CONSTRAINT [Primary-key-Constraint-Name] PRIMARY KEY CLUSTERED    &lt;br /&gt;(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; [Grouping-Key],     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; [Grouped-Identity-Key]     &lt;br /&gt;) &lt;/p&gt;  &lt;p&gt;ON [Partition-Scheme](Grouping-Key)&lt;/p&gt;  &lt;p&gt;And storage-aligning the other indexes can be done by just referencing the grouping-key in the same way.&lt;/p&gt;  &lt;p&gt;This would cause the GroupdIdentityKey to reset back to the initial value each time the Grouping-key changes.&amp;#160; The table could then easily be partitioned on the grouping-key, which can be very compact to just do the partitioning, such as the year from an order date.&lt;/p&gt;  &lt;p&gt;Thought on this? Is there a way to accomplish this that I am missing?&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:c5ee4f30-d4d2-43bf-9733-1e47083363fa" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SQL+Server+2008" rel="tag"&gt;SQL Server 2008&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server+Enhancement+Suggestions" rel="tag"&gt;SQL Server Enhancement Suggestions&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Partitioning" rel="tag"&gt;SQL Partitioning&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9882744" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2005/default.aspx">SQL Server 2005</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+Performance/default.aspx">SQL Server Performance</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+Indexing/default.aspx">SQL Server Indexing</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Performance/default.aspx">SQL Performance</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Partitioning/default.aspx">SQL Partitioning</category></item><item><title>A Wrapper for Running SQL Server 2008 Reporting Services Reports Anonymously</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/20/a-wrapper-for-running-sql-server-2008-reporting-services-reports-anonymously.aspx</link><pubDate>Thu, 20 Aug 2009 22:23:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9877640</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9877640.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9877640</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9877640</wfw:comment><description>&lt;P&gt;With SQL Server 2008, Microsoft re-architected SQL Server Reporting Services (SSRS) to no longer have an IIS dependency.&amp;nbsp; It now relies directly on HTTP.SYS and handles web protocols independently.&amp;nbsp;&amp;nbsp; This is a good thing, in a lot of respects (see &lt;A title=http://msdn.microsoft.com/en-us/library/bb630410.aspx href="http://msdn.microsoft.com/en-us/library/bb630410.aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb630410.aspx"&gt;http://msdn.microsoft.com/en-us/library/bb630410.aspx&lt;/A&gt;).&amp;nbsp; But, there is also a down-side for those of us who are used to utilizing the IIS framework for hosting SQL Server reports.&amp;nbsp; For one thing, allowing anonymous access to reports just by configuring an IIS virtual directory mapping is gone.&amp;nbsp; Also, client certificates are no longer supported, which is a big deal if you’re in an environment where these are used (like I am).&lt;/P&gt;
&lt;P&gt;There have already been a few articles written about anonymous access for SSRS 2008, and a couple of techniques to allow Report-manager type access (see &lt;A title=http://blogs.msdn.com/jameswu/archive/2008/07/15/anonymous-access-in-sql-rs-2008.aspx href="http://blogs.msdn.com/jameswu/archive/2008/07/15/anonymous-access-in-sql-rs-2008.aspx" mce_href="http://blogs.msdn.com/jameswu/archive/2008/07/15/anonymous-access-in-sql-rs-2008.aspx"&gt;http://blogs.msdn.com/jameswu/archive/2008/07/15/anonymous-access-in-sql-rs-2008.aspx&lt;/A&gt;,&amp;nbsp; &lt;A title=http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx href="http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx" mce_href="http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx"&gt;http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx&lt;/A&gt;).&amp;nbsp; Rather than rehashing them, my purpose in this post is to provide a generic solution for accomplishing anonymous access to your reports, without compromising your server security, and something you can tailor to your environment.&amp;nbsp; Although my goal with this is to simply provide anonymous access, you can use this same technique for other purposes such as allowing smart-card logon to the hosting web site, since essentially the limitations related to accessing SSRS related to the authentication are wrapped in an ASP.NET application that does live off of IIS.&lt;/P&gt;
&lt;P&gt;The basic concept is to take the SSRS report manager and wrap up the core functionality for executing reports inside of an ASP.NET web page that dynamically discovers and presents the reports and report folders in the same manner that the Report Manager does and then allow them to be executed.&amp;nbsp; It does not provide all the functionality of Report Manager, such as the report management aspects, but you could tailor this to add that.&amp;nbsp; Obviously for an anonymous-access scenario, most of those management functions don’t make sense, since they are associated with the identity of the user.&lt;/P&gt;
&lt;P&gt;I’ve posted the solution on the web site &lt;A title=http://www.bobthesis.com/reportsportal/ href="http://www.bobthesis.com/reportsportal/" mce_href="http://www.bobthesis.com/reportsportal/"&gt;http://www.bobthesis.com/reportsportal/&lt;/A&gt; if you want to actually see how this in action.&amp;nbsp; The menu user-interface is not pretty, but I’m not a web-designer, you can easily improve the cosmetics for that by modifying the master page/styles.&amp;nbsp; The demo uses the Adventure Works samples, but you’ll find as we go through the code, there is nothing specific to Adventure works, other than an entry in the config file that indicates the name of the Adventure Works reports folder as the root folder.&lt;/P&gt;
&lt;P&gt;So, let’s step through the solution.&amp;nbsp; There are 7 main components to the solution:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Reporting Services Web Service: The SQL Server Reporting Web Services (ReportingService2005.asmx – that’s right, 2005, it has not been changed for 2008) provides the interface for enumerating the reports and report folders.&amp;nbsp; It provides a host of other capabilities for report execution, rendering and management, but that is the only capability we need for our solution. &lt;/LI&gt;
&lt;LI&gt;The ReportViewer Control: This is a control that we integrate into our ASP.NET solution.&amp;nbsp; It provides the user experience for executing the reports including prompting for the parameters and providing the various options. &lt;/LI&gt;
&lt;LI&gt;A custom class for authenticating to the Reporting Web Service.&amp;nbsp; This is what allows us to wrap the authentication in the ASP.NET page for the Report Viewer control to use to connect to the Reporting Service web service. &lt;/LI&gt;
&lt;LI&gt;An ASP.NET tree-view control for displaying a menu hierarchy for running the reports corresponding to the reporting folder structure defined in SSRS for the particular reporting application. &lt;/LI&gt;
&lt;LI&gt;A master page that includes the tree view control &lt;/LI&gt;
&lt;LI&gt;A default.aspx page that includes code to execute the Reporting Services web service and enumerate the results. &lt;/LI&gt;
&lt;LI&gt;A config file along with entries to define the authentication parameters. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Below is the overall architecture showing the main components.&amp;nbsp; The dashed curved lines represent data flows, solid lines represent composition, dashed lines represent inheritance, and curved non-dashed line represent process flow.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_4.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_4.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_1.png" width=585 height=772 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Now, let’s walk through the development of the components, I’m assuming you’re familiar with Visual Studio.NET so will not delve into the details related to the IDE.&lt;/P&gt;
&lt;P&gt;First, we create a ASP.NET application project in Visual Studio.NET and we’ll call it ReportsPortal (You could also use a web site project type if you prefer).&amp;nbsp; At this point, we have our web.config and default.aspx.&amp;nbsp; Next, add a master page to the project.&amp;nbsp; At this point, our project structure should like this:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_16.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_16.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_7.png" width=182 height=156 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_7.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Next, add a reference to the ReportingService2005.asmx.&amp;nbsp; For now, we will use the local machine to create the web service reference.&amp;nbsp; However, we can modify this later to point to a different server, which is what I do for my demo solution.&amp;nbsp; My reporting web service is on a different server than my web server.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_10.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_10.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_4.png" width=644 height=451 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_4.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Now, our solution should look as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_18.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_18.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_8.png" width=174 height=210 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_8.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Now, let’s setup our master page to have place holders for our menu and our report viewer.&amp;nbsp; For my demo, I provide the navigation interface on the left side bar and the report viewer on the right side.&amp;nbsp; I use a table control to divide the placeholders and insert the tree navigation control on the left as shown below:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_14.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_14.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_6.png" width=644 height=237 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_6.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Below is the source code for the Master Page after setting a few properties to make the tree view not completely vanilla:&lt;/P&gt;
&lt;STYLE type=text/css&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&lt;SPAN class=asp&gt;&amp;lt;%@ Master Language="C#" AutoEventWireup="true" 
CodeBehind="ReportsPortal.master.cs" 
Inherits="ReportsPortal.ReportsPortal" %&amp;gt;&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;&amp;lt;!&lt;/SPAN&gt;&lt;SPAN class=html&gt;DOCTYPE&lt;/SPAN&gt; &lt;SPAN class=attr&gt;html&lt;/SPAN&gt; &lt;SPAN class=attr&gt;PUBLIC&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;"-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;/SPAN&gt; 
&lt;SPAN class=kwrd&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;html&lt;/SPAN&gt; &lt;SPAN class=attr&gt;xmlns&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="http://www.w3.org/1999/xhtml"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;head&lt;/SPAN&gt; &lt;SPAN class=attr&gt;runat&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="server"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
   
    &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;style&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;style&lt;/SPAN&gt; &lt;SPAN class=attr&gt;type&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="text/css"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
        .style1
        {
            font-family: "Comic Sans MS";
            height: 351px;
        }
        .style2
        {
            font-family: "Lucida Console";
            font-size: large;
            text-align: center;
        }
    &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;style&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;head&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;body&lt;/SPAN&gt; &lt;SPAN class=attr&gt;bgcolor&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="#f9f9f9"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;form&lt;/SPAN&gt; &lt;SPAN class=attr&gt;id&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="form1"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;runat&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="server"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;div&lt;/SPAN&gt; &lt;SPAN class=attr&gt;class&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="style2"&lt;/SPAN&gt; 
        &lt;SPAN class=attr&gt;style&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="background-color: #6699FF; font-family: 'Microsoft Sans Serif'; &lt;BR&gt;font-size: large; color: #800000;"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
        Anonymous SQL Server 2008 Reporting Services Wrapper&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;div&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;table&lt;/SPAN&gt; &lt;SPAN class=attr&gt;class&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="style1"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;tr&lt;/SPAN&gt; &lt;SPAN class=attr&gt;valign&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="top"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;td&lt;/SPAN&gt; &lt;SPAN class=attr&gt;bgcolor&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="#E1FFF7"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:TreeView&lt;/SPAN&gt; &lt;SPAN class=attr&gt;ID&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="TreeView1"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;runat&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="server"&lt;/SPAN&gt; 
                        &lt;SPAN class=attr&gt;NodeIndent&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="10"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;ShowLines&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="true"&lt;/SPAN&gt;  &lt;BR&gt;&lt;SPAN class=attr&gt;ImageSet&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="BulletedList4"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
                        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;HoverNodeStyle&lt;/SPAN&gt; &lt;SPAN class=attr&gt;BackColor&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="#339966"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
                        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;SelectedNodeStyle&lt;/SPAN&gt; &lt;SPAN class=attr&gt;BackColor&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="#666699"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:TreeView&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;td&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;td&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:ContentPlaceHolder&lt;/SPAN&gt; &lt;SPAN class=attr&gt;ID&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="ContentPlaceHolder1"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;runat&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="server"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
        
        &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:ContentPlaceHolder&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;td&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;tr&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;table&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;form&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;body&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;html&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;






.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;Before, we can start writing the code to use the web service to return our report items and before we can start using the Report Viewer Control, let’s put in the “plumbing” in our web.config, add the report viewer control to the the form, ensure we have the necessary reporting services references and leverage the authentication interface.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Here are the web config entries, we create for both defining the starting location for our report menu as well as the user authentication settings for the proxy reporting user.&amp;nbsp; We need to add the ApplicationSettings section to the config file, which I stick on the bottom.&amp;nbsp; Of course, you should use an account wiht minimal user rights as your proxy reporting user, and you may want to use the .NET DPAPI encryption capabilities to encrypt your web.config file (see &lt;A title=http://www.dotnetcurry.com/ShowArticle.aspx?ID=185&amp;amp;AspxAutoDetectCookieSupport=1 href="http://www.dotnetcurry.com/ShowArticle.aspx?ID=185&amp;amp;AspxAutoDetectCookieSupport=1" mce_href="http://www.dotnetcurry.com/ShowArticle.aspx?ID=185&amp;amp;AspxAutoDetectCookieSupport=1"&gt;http://www.dotnetcurry.com/ShowArticle.aspx?ID=185&amp;amp;AspxAutoDetectCookieSupport=1&lt;/A&gt; for more info on encrypting .net config files), although since these are anonymous reports anyways, it isn’t critical, as long as the proxy reporting user has very limited rights.&amp;nbsp; The report user account should be a normal user account and have permissions in the SQL database to the stored procedures, views, tables, required to run the various reports as well as have browser permissions to the Report Server.&amp;nbsp; If you don’t have an instance name remove the “_myinstance” part of the report service url.&amp;nbsp; Notice we have to repeat the server url in 2 different formats – 1 for the web service reference including the reportservice2005.asmx and the other just containing the root location.&amp;nbsp; The second one is used by the authentication interface and it will not work with the full web service url.&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;applicationSettings&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;ReportsPortal.Properties.Settings&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
         &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt; &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="ReportsPortal_WsReportService_ReportingService2005"&lt;/SPAN&gt;
              &lt;SPAN class=attr&gt;serializeAs&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="String"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;http://myServer/ReportServer_myinstance/ReportService2005.asmx&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
          &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
          &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt; &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="MyReportServerUrl"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;serializeAs&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="String"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;http://myServer/ReportServer_myinstance&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
          &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt; &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="ReportsRootPath"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;serializeAs&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="String"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;/&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt; &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="TopLevelMenuText"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;serializeAs&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="String"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;AdventureWorks Reports&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt; &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="MyReportViewerPassword"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;serializeAs&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="String"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;myPassword&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt; &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="myReportViewerUser"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;serializeAs&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="String"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;FONT color=#000000&gt;myreportUser&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt; &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="MyReportViewerDomain"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;serializeAs&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="String"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;mydomain&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;setting&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;ReportsPortal.Properties.Settings&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;applicationSettings&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;However, in addition to the above standard application settings, we need to create a special configuration setting for the ReportServerConnection interface in the appsettings section.&amp;nbsp; (see xxx).&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Below is in the part of the config file higher up and before system.web:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;appSettings&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;add&lt;/SPAN&gt; &lt;SPAN class=attr&gt;key&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="ReportViewerServerConnection"&lt;/SPAN&gt; &lt;BR&gt;&lt;SPAN class=attr&gt;value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="MyReportServerConnection, ReportsPortal"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;appSettings&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;  &lt;/PRE&gt;
&lt;STYLE type=text/css&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;In this case, “My ReportServerConnection” refers to the name of the class file that you create to implement the IreportServerConnection interface and “ReportsPortal” and “ReportsPortal” refers to the name of the assembly for your web application.&lt;/P&gt;
&lt;P&gt;I know this is a bit confusing, so I’ve included all of the code in a zip file that you download when you get to the end of the article…)&lt;/P&gt;
&lt;P&gt;Note, you can also use the Settings approach to create these and then use the Properties.Default.Settings to access the values rather than using the Configuration Manager method.&lt;/P&gt;
&lt;P&gt;Next, let’s add the ReportViewer control to the default.aspx page.&amp;nbsp; Set the property on the default.aspx page to use the ReportsPortal master page, so we should have 1 placeholder to work with and we drag the Microsoft report viewer control from the Reporting section of the toolbox onto the form.&amp;nbsp; When we drag the control on the form, it will update our project to include a reference to the Microsoft.ReportViewer.WebForms assembly as well as update our web.config with the assembly information.&lt;/P&gt;
&lt;P&gt;So, now our default.aspx should look like below, we don’t need to set any properties as this will all happen dynamically in the code, however, you will probably want to increase the width and add zoom mode to make the user experience better.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_20.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_20.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_9.png" width=487 height=484 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_9.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Below is the source of the default.aspx including some property settings for the report viewer rendering:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=asp&gt;&amp;lt;%@ Page Language="C#" AutoEventWireup="true" 
CodeBehind="Default.aspx.cs" Inherits="ReportsPortal._Default" 
MasterPageFile="~/ReportsPortal.Master" %&amp;gt;&lt;/SPAN&gt;

&lt;SPAN class=asp&gt;&amp;lt;%@ Register assembly="Microsoft.ReportViewer.WebForms, 
Version=9.0.0.0, Culture=neutral, 
PublicKeyToken=b03f5f7f11d50a3a" 
namespace="Microsoft.Reporting.WebForms" 
tagprefix="rsweb" %&amp;gt;&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:Content&lt;/SPAN&gt; &lt;SPAN class=attr&gt;ID&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Content1"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;runat&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="server"&lt;/SPAN&gt; 
    &lt;SPAN class=attr&gt;contentplaceholderid&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="ContentPlaceHolder1"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:Label&lt;/SPAN&gt; &lt;SPAN class=attr&gt;ID&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="ReportLabel"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;runat&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="server"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:Label&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;rsweb:ReportViewer&lt;/SPAN&gt; &lt;SPAN class=attr&gt;ID&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="ReportViewer1"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;runat&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="server"&lt;/SPAN&gt; 
    &lt;SPAN class=attr&gt;SizeToReportContent&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="True"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="800px"&lt;/SPAN&gt; 
    &lt;SPAN class=attr&gt;ZoomMode&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="PageWidth"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Height&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="600px"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;rsweb:ReportViewer&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;asp:Content&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;Now, let’s take a look at the authentication interface portion.&amp;nbsp; I use the ReportServerConnection2 interface because it supports stateless reporting and seems the most robust, there are others that can be used (see &lt;A title=http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx href="http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx" mce_href="http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx"&gt;http://blogs.msdn.com/brianhartman/archive/2008/11/21/custom-credentials-in-the-report-viewer.aspx&lt;/A&gt;).&amp;nbsp; To get it to compile, you will need to add a reference to the Microsoft.ReportViewer class.&amp;nbsp; Here is the code for the MyReportServerConnection.cs class (you can use different names, but remember everything has to be in sync with the config setting that references back to the class).&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;FONT face="Arial Narrow"&gt;&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Collections.Generic;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Linq;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web.UI;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web.UI.WebControls;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.Reporting.WebForms;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Net;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Security.Principal;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Configuration;

&lt;SPAN class=kwrd&gt;namespace&lt;/SPAN&gt; ReportsPortal
{
    [Serializable]
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; MyReportServerConnection : IReportServerConnection2
    {
        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; Uri ReportServerUrl
        {
            get
            {
                &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; url = Properties.Settings.Default.MyReportServerUrl;
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(url))
                    &lt;SPAN class=kwrd&gt;throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Exception(&lt;SPAN class=str&gt;"Missing url from the Web.config file"&lt;/SPAN&gt;);
                &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Uri(url);
            }
        }
        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; Timeout
        {
            &lt;SPAN class=rem&gt;// set timeout to 60 seconds&lt;/SPAN&gt;
            get { &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; 60000; }
        }

        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; IEnumerable&amp;lt;Cookie&amp;gt; Cookies
        {
            &lt;SPAN class=rem&gt;// No custom cookies&lt;/SPAN&gt;
            get { &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;; }
        }
        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; IEnumerable&amp;lt;&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;&amp;gt; Headers
        {
            &lt;SPAN class=rem&gt;// No custom headers&lt;/SPAN&gt;
            get { &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;; }
        }

        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; MyReportServerConnection()
        {
        }


        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; WindowsIdentity ImpersonationUser
        {
            get { &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;; }
        }

        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; ICredentials NetworkCredentials
        {
            get
            {
                &lt;SPAN class=rem&gt;// return null will force the use of impersonation, &lt;/SPAN&gt;
                &lt;SPAN class=rem&gt;// otherwise, remove the return null and &lt;/SPAN&gt;
                &lt;SPAN class=rem&gt;// implement the other app settings to specify the credential details&lt;/SPAN&gt;
                &lt;SPAN class=rem&gt;// return null;&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName = Properties.Settings.Default.myReportViewerUser;
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(userName))
                    &lt;SPAN class=kwrd&gt;throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Exception(&lt;SPAN class=str&gt;"Missing user name from Web.config file"&lt;/SPAN&gt;);
                &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; password = Properties.Settings.Default.MyReportViewerPassword;
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(password))
                    &lt;SPAN class=kwrd&gt;throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Exception(&lt;SPAN class=str&gt;"Missing password from Web.config file"&lt;/SPAN&gt;);
                &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; domain = Properties.Settings.Default.MyReportViewerDomain;
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(domain))
                    &lt;SPAN class=kwrd&gt;throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Exception(&lt;SPAN class=str&gt;"Missing domain from Web.config file"&lt;/SPAN&gt;);
                &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; NetworkCredential(userName, password, domain);
            }
        }

        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; GetFormsCredentials(&lt;BR&gt;         &lt;SPAN class=kwrd&gt;out&lt;/SPAN&gt; Cookie authCookie, &lt;BR&gt;&lt;SPAN class=kwrd&gt;         out&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName, &lt;BR&gt;&lt;SPAN class=kwrd&gt;         out&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; password, &lt;BR&gt;&lt;SPAN class=kwrd&gt;         out&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; authority)
        {
            authCookie = &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;;
            userName = &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;;
            password = &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;;
            authority = &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;;
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;;
        }
    }
}&lt;/FONT&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;









.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;The project should now look something like below:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_22.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_22.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_10.png" width=290 height=484 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb_10.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Now, that the plumbing is done, we can focus on the 2 other pieces of code.&amp;nbsp; First, lets do the code to enumerate the reporting services folder and return the lists into the treeview control.&amp;nbsp; This is the heart of the application as this basically wraps the Report Manager user interface for navigating reports and folders.&amp;nbsp; We put the enumeration code in the Master page .cs (ReportsPortal.Master.cs in our case).&amp;nbsp; The Page_load just clears out the menu and repopulates it from the Report Server by calling BuildNavigation as long as this is not just a postback event.&amp;nbsp; The not postback helps the performance by only doing this when first executing the application.&amp;nbsp; The tree view control will contain all of the folders along with the items arranged hierarchically.&amp;nbsp; Each report item then maps to a navigation url that contains a link back to the default.aspx passing in the full report item path.&amp;nbsp; We can leverage the same credentials from the config file for invoking the report service as we do for running the reports.&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Collections.Generic;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Linq;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web.UI;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web.UI.WebControls;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; ReportsPortal.WsReportService;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Security;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Net;


&lt;SPAN class=kwrd&gt;namespace&lt;/SPAN&gt; ReportsPortal
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;partial&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; ReportsPortal : System.Web.UI.MasterPage
    {
        &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Page_Load(&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; sender, EventArgs e)
        {
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!Page.IsPostBack)
            {
                TreeView1.Nodes.Clear();
                TreeView1.Nodes.Add(&lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; TreeNode
                    (Properties.Settings.Default.TopLevelMenuText,
                    Properties.Settings.Default.ReportsRootPath));
                BuildNavigation(TreeView1.Nodes[0]);
            }
        }

        &lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; BuildNavigation(TreeNode parentNode)
        {

            &lt;SPAN class=rem&gt;// Enumerate all of the folders and add the reports&lt;/SPAN&gt;
            WsReportService.ReportingService2005 ws =
                &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; WsReportService.ReportingService2005();&lt;BR&gt;// Need to pass in credentials for reporting service.
            NetworkCredential cred = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; NetworkCredential(
                    Properties.Settings.Default.myReportViewerUser,
                    Properties.Settings.Default.MyReportViewerPassword,
                    Properties.Settings.Default.MyReportViewerDomain);
            
            ws.Credentials = cred;
            CatalogItem[] items = ws.ListChildren(parentNode.Value, &lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;);
            &lt;SPAN class=kwrd&gt;foreach&lt;/SPAN&gt; (CatalogItem item &lt;SPAN class=kwrd&gt;in&lt;/SPAN&gt; items)
            {
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (item.Name != &lt;SPAN class=str&gt;"Data Sources"&lt;/SPAN&gt;)
                {
                    &lt;SPAN class=kwrd&gt;switch&lt;/SPAN&gt; (item.Type)
                    {
                        &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; ItemTypeEnum.Report:
                            parentNode.ChildNodes.Add
                                (&lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; TreeNode(
                                    item.Name,
                                    item.Path,
                                    &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;,
                                    &lt;SPAN class=str&gt;"Default.Aspx?Report="&lt;/SPAN&gt;
                                    + item.Path, &lt;SPAN class=str&gt;"_top"&lt;/SPAN&gt;));
                            &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
                        &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; ItemTypeEnum.Folder:
                            TreeNode newParentNode = &lt;BR&gt;&lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; TreeNode(item.Name, item.Path);
                            parentNode.ChildNodes.Add(newParentNode);
                            BuildNavigation(newParentNode);
                            &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
                        &lt;SPAN class=kwrd&gt;default&lt;/SPAN&gt;:
                            &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
                    }
                }
            }
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt;;
        }

    }
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;Next, we make sure our default.aspx is set Now, we can bring it all together in the default.aspx.cs by doing a page load to evaluate the query string that gets set by the master page navigator when the user selects the link.&amp;nbsp; It then instantiates the MyReportServerConnection class and maps the credentials back to the Server report that needs to be run.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Collections.Generic;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Linq;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web.UI;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Web.UI.WebControls;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.Reporting.WebForms;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Net;


&lt;SPAN class=kwrd&gt;namespace&lt;/SPAN&gt; ReportsPortal
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;partial&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; _Default : System.Web.UI.Page
    {

        &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Page_Load(&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; sender, EventArgs e)
        {

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; ((!IsPostBack) &amp;amp;&amp;amp; Request.QueryString.Count &amp;gt; 0)
            {
                &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; reportPath = Request.QueryString[0];
                &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ReportLabel.Text = Request.QueryString[0];
                &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ReportViewer1.ProcessingMode = ProcessingMode.Remote;
                MyReportServerConnection rsc = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; MyReportServerConnection();
                &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ReportViewer1.ServerReport.ReportServerCredentials = rsc;
                &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ReportViewer1.ServerReport.ReportPath = reportPath;
                &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ReportViewer1.ServerReport.ReportServerUrl =
                    &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Uri((Properties.Settings.Default.MyReportServerUrl));
                &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ReportViewer1.ServerReport.Refresh();
            }
        }
    }
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;Before testing this out, we need to validate that permissions are correct for our demonstration report user.&amp;nbsp; The account will need to have local logon rights for example.&amp;nbsp; If you’re going across firewall boundaries, you’ll probably need to either setup the reports as not requiring credentials and use an execution account, or use SSL with a certificate so you can use basic authentication on the web service without worrying about credentials in the clear.&lt;/P&gt;
&lt;P&gt;You can setup an execution account by using the Report Server configuration manager as shown below.&amp;nbsp; If you do this, then you might not even have to bother with the special interface for the connection, but I haven’t tested that yet.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image43.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image43.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image43_thumb.png" width=244 height=196 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image43_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;So, here is the end result, Yes, the treeview menu interface isn’t pretty, but it works, and it automatically enumerates down to the lowest folders.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_2.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_2.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb.png" width=519 height=484 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/AWrapperforRunningSQLServer2008Reporting_8502/image_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Try it for yourself at &lt;A title=http://www.bobthesis.com/reportsportal/ href="http://www.bobthesis.com/reportsportal/" mce_href="http://www.bobthesis.com/reportsportal/"&gt;http://www.bobthesis.com/reportsportal/&lt;/A&gt;&lt;/P&gt;
&lt;DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:0767317B-992E-4b12-91E0-4F059A8CECA8:20b4a239-b15d-4bd3-b4b4-2371be89a224 class=wlWriterEditableSmartContent&gt;Technorati Tags: &lt;A href="http://technorati.com/tags/SSRS" rel=tag mce_href="http://technorati.com/tags/SSRS"&gt;SSRS&lt;/A&gt;,&lt;A href="http://technorati.com/tags/SQL+Server+Reporting+Services" rel=tag mce_href="http://technorati.com/tags/SQL+Server+Reporting+Services"&gt;SQL Server Reporting Services&lt;/A&gt;&lt;/DIV&gt;
&lt;STYLE type=text/css&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9877640" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/microsoftbob/attachment/9877640.ashx" length="78152" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/CodeProject/default.aspx">CodeProject</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Visual+Studio.NET/default.aspx">Visual Studio.NET</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+Reporting+Services/default.aspx">SQL Server Reporting Services</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SSRS/default.aspx">SSRS</category></item><item><title>Cautions with Indexed Views</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/15/cautions-with-indexed-views.aspx</link><pubDate>Sat, 15 Aug 2009 18:32:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9871131</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9871131.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9871131</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9871131</wfw:comment><description>&lt;p&gt;If you’ve been following my blog, you may remember an article I did extolling the virtues of indexed views - &lt;a title="http://blogs.msdn.com/microsoftbob/archive/2009/05/13/sql-data-warehousing-tip-2-indexed-views.aspx" href="http://blogs.msdn.com/microsoftbob/archive/2009/05/13/sql-data-warehousing-tip-2-indexed-views.aspx"&gt;http://blogs.msdn.com/microsoftbob/archive/2009/05/13/sql-data-warehousing-tip-2-indexed-views.aspx&lt;/a&gt;.&amp;#160; I stand behind that and have found this feature extremely useful.&amp;#160; In fact in my last post the 11 seconds it was taking to perform a few thousand transactions against a 10-million row history table with 3 million transaction went down to just 2 seconds using an indexed view.&lt;/p&gt;  &lt;p&gt;However, before you go out and make every view into an indexed view, it is important to understand what an indexed view is and what are the consequences.&amp;#160; I was reminded of this very sharply when I did the following “routine” update command on my table containing all of the trading symbols used for my simulation processing:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;/*------------------------&lt;br /&gt;update dbo.EquitySymbol &lt;br /&gt;set Shortable = 1 &lt;br /&gt;from Load.ShortableList l&lt;br /&gt;where l.Symbol = dbo.EquitySymbol.TradingSymbol&lt;br /&gt;------------------------*/ &lt;/pre&gt;

&lt;p&gt;(6334 row(s) affected)&lt;/p&gt;

&lt;p&gt;Now, normally this had been taking less than 2 seconds.&amp;#160; But, this was before I added the indexed view that happened to include the “Shortable” column.&amp;#160; So, how long did it take with the indexed view in place?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/CautionswithIndexedViews_78AF/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/CautionswithIndexedViews_78AF/image_thumb.png" width="244" height="46" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Almost 19 minutes?&amp;#160; Yes, 18 minutes and 51 seconds?&amp;#160; That is actually about twice as long than it takes to create the indexed view along with all of it’s alternate indexes!&amp;#160; Pardon the drama, but my point is that Indexed views are dramatic by their nature.&amp;#160; They are dramatic in that on one hand you can analyze millions of rows and help enabling performing something as complex as generating 7 years of trading simulations consisting of over 3 million orders for 10 million rows in a space of a couple of hours, while on the other hand causing a small update to take over a thousand times longer than usual…&lt;/p&gt;

&lt;p&gt;So, how do we explain this?&amp;#160; First, we need to understand what happens when you create an indexed view.&amp;#160; The first step is to enable schemabinding on the view.&amp;#160; This ensures that SQL can tag a dependency between the table and the view so it can prevent and detect changes that might cause the view to stop functioning, that isn’t where the performance hit comes, (see &lt;a title="http://msdn.microsoft.com/en-us/library/ms187956.aspx" href="http://msdn.microsoft.com/en-us/library/ms187956.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms187956.aspx&lt;/a&gt; for an explanation of the process for creating an indexed view including the schemabinding step).&amp;#160; The key threshold happens (pun intended) when you create the primary key for the view which is the unique clustered index for the view and required before you can add secondary indexes to the view.&amp;#160; What that does it “materializes” the view such that it is no longer just a query into your tables, but it becomes a table itself with real data.&amp;#160; And of course, that data must be maintained to match the underlying tables.&amp;#160; &lt;/p&gt;

&lt;p&gt;So, what was the situation in my case?&amp;#160; Well, the “shortable” flag was part of the indexed view that joined the equity symbol table (which has about 9,000 rows) to the Equity History table, which happens to have about 10 million rows.&amp;#160; My “little” update of the 6,000 or so Equity Symbol rows cascaded into about 7 million updates necessary to maintain all of the rows in the indexed view.&amp;#160; Here you can see the major time-consuming aspects of the query plan with the indexed view in place:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/CautionswithIndexedViews_78AF/image_4.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/CautionswithIndexedViews_78AF/image_thumb_1.png" width="244" height="185" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Notice the large time for the sorts, these were apparently needed to prepare for secondary index updates that included the shortable column as an included column.&amp;#160; And notice that the update time for the clustered index for the table actually containing the column ([EquitySymbol].[PK_EquitySymbol]) is estimated to take virtually 0 percent of the total query time.&lt;/p&gt;

&lt;p&gt;So, what does this mean – avoid indexed views?&amp;#160; Not at all!&amp;#160; It just means as the title suggest: use caution.&amp;#160; So what could I have done differently to avoid this issue.&amp;#160; To start with, my update command is flawed.&amp;#160; I told SQL to update every row and didn’t even look to see if the rows needed to be updated.&amp;#160; SQL Server will happily do what you tell it to, it doesn’t have a built-in mechanism that says - “Hey, you don’t need to update that column, it already contains the value you specified”.&amp;#160; It doesn’t do that for a very good reason.&amp;#160; For example, what if I had a trigger on a table that checked to see if a particular column was updated.&amp;#160; Since SQL trigger processing with the “IF UPDATE(column)” doesn’t check to see if the value is actually changed, just whether it is updated, it is easy for me to force a trigger to execute just by updating the column to its current value.&amp;#160; So, what I should have done was:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;update&lt;/span&gt; dbo.EquitySymbol 
&lt;span class="kwrd"&gt;set&lt;/span&gt; Shortable = 1 
&lt;span class="kwrd"&gt;from&lt;/span&gt; &lt;span class="kwrd"&gt;Load&lt;/span&gt;.ShortableList l
&lt;span class="kwrd"&gt;where&lt;/span&gt; l.Symbol = dbo.EquitySymbol.TradingSymbol
&lt;font color="#ff0000"&gt;&lt;span class="kwrd"&gt;AND&lt;/span&gt; dbo.EquitySymbol.Shortable &amp;lt;&amp;gt; 1&lt;/font&gt;&lt;/pre&gt;

&lt;p&gt;&lt;font color="#000000"&gt;Since there were only a handful of rows that had changed since the last time this update command was run, doing it this way, should have taken only a few seconds, albeit it still would have required a couple thousand updates to cascade the updates to the related rows the view.&amp;#160; Another option is that if I really did need to update a few thousand rows, would have been to simply drop the indexed view, perform the update, and recreate the indexed again.&amp;#160; There may be some more exotic approaches such as disabling the indexes on the indexed view, but effectively the approach is the same.&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;So, here are a few suggestions when dealing with indexed views:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Do not include more columns than you really need, particularly if the columns may be subject to change.&lt;/li&gt;

  &lt;li&gt;Consider the cardinality of the values in the indexed view.&amp;#160; If your indexed view ends up repeating a few value thousands of times, consider the source of the data.&amp;#160; If that data is often changed, then expect those updates to take many times longer than without the indexed view.&amp;#160; Be very careful when joining a table with relatively few rows (i.e. 6,000) that is frequently updated to a much larger table (i.e. 10 million), even if the larger table is infrequently updated.&lt;/li&gt;

  &lt;li&gt;Consider carefully the use of low-cardinality items in the indexes either as segments of the indexes or as included columns, as this will add to the update time for the view.&lt;/li&gt;

  &lt;li&gt;Don’t create an indexed view unless there is at least one critical query that can benefit significantly and measure that benefit against the cost of other queries that may need to update the table.&amp;#160; &lt;/li&gt;

  &lt;li&gt;When considering the costs/benefit of an indexed view, don’t forget to factor in that SQL will use the indexed view for queries that do not directly reference the indexed view.&amp;#160; Absent a query hint to indicate otherwise, SQL Server will leverage the indexed view in query plans that access any tables related to the indexed view.&amp;#160; So, when you create an indexed view intended to help one query, you may find it helping other queries as well.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, the bottom line is that like just about everything else in SQL Server 2008, indexed views have their place, but use them wisely…&lt;/p&gt;

&lt;p&gt;
  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e28432a6-8e82-4671-87ed-3630aaeee36a" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Indexed+Views" rel="tag"&gt;Indexed Views&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server+2008" rel="tag"&gt;SQL Server 2008&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server" rel="tag"&gt;SQL Server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server+Performance" rel="tag"&gt;SQL Server Performance&lt;/a&gt;&lt;/div&gt;
  &lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9871131" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Performance/default.aspx">SQL Performance</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Indexed+Views/default.aspx">Indexed Views</category></item><item><title>Some Uses for Query Hints</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/14/some-uses-for-query-hints.aspx</link><pubDate>Fri, 14 Aug 2009 08:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9869385</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9869385.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9869385</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9869385</wfw:comment><description>&lt;P&gt;Some of you are all set to flame me just because of my title. I know because a couple of years back, I would have probably been one of the first to say “NO!”, when anybody started talking about query hints.&amp;nbsp; But, like everything else in this world, they have their place.&amp;nbsp; First of all, I encourage you to try everything else before resorting to query hints and to avoid hints that specify index names and such directly.&amp;nbsp; The hints I have found to be most useful are fairly generic and do not impose maintenance burdens on the database structure.&lt;/P&gt;
&lt;P&gt;The rest of you may be wondering exactly what I’m talking about, so let me explain.&amp;nbsp;&amp;nbsp; When SQL Server evaluates a query, it takes it apart and looks for how it can optimize the retrieval, what indexes can be used.&amp;nbsp; It looks at all sorts of things including selectivity of the indexes, number of physical and logical I/Os required, the parameter values, the search arguments (SARGs) and makes a best-guess stab.&amp;nbsp; Any query you execute, you can select the “Show Query Plan” menu item (or CTRL-L) and get a graphical picture of just how SQL will execute the query.&amp;nbsp; You can also save it in XML format.&amp;nbsp; And it will actually detect “missing indexes”, indexes that would help performance, which I have found incredibly useful and powerful (although I don’t usually follow the index suggestions verbatim – more about that in another post).&amp;nbsp; A query hint is basically telling the query optimizer that you have inside information that is better than what SQL knows.&amp;nbsp; For more background on query plans, query optimization, etc, I suggest the book SQL Server 2008 Internals” by Karen Delaney (&lt;A title=http://search.barnesandnoble.com/booksearch/results.asp?ATH=Kalen+Delaney href="http://search.barnesandnoble.com/booksearch/results.asp?ATH=Kalen+Delaney" mce_href="http://search.barnesandnoble.com/booksearch/results.asp?ATH=Kalen+Delaney"&gt;http://search.barnesandnoble.com/booksearch/results.asp?ATH=Kalen+Delaney&lt;/A&gt;).&amp;nbsp;&amp;nbsp; The SQL team has also created a special blog focused on query optimization at &lt;A title=http://blogs.msdn.com/queryoptteam/ href="http://blogs.msdn.com/queryoptteam/" mce_href="http://blogs.msdn.com/queryoptteam/"&gt;http://blogs.msdn.com/queryoptteam/&lt;/A&gt;.&amp;nbsp; Understanding query plans and every single different hints are long blog posts in and of themselves, so I’m not going to attempt to cover this in this article.&lt;/P&gt;
&lt;P&gt;My recent experience with query hints came in 2 different areas.&amp;nbsp; Alas, I actually have stats to backup one of my observations.&amp;nbsp; The first observation involved the use of the FAST N hint.&amp;nbsp; This basically tells SQL to optimize only for the first N matches.&amp;nbsp; This can be real useful when using a TOP N where N is a parameter value and you happen to know that it will usually be a small number of rows.&amp;nbsp; SQL doesn’t have the knowledge of that luxury, so forcing an OPTION N hint will cause the optimizer to do SEEKs instead of SCANs which (and I am oversimplifying) means it goes right to the page with the page with the first N matches rather than trying to scan through an entire range or entire table.&amp;nbsp; This can also be useful for partitioning/ranking queries where again you are looking for just the first few rows and not wanting to rank the entire set.&lt;/P&gt;
&lt;P&gt;The other experience involved the use of my simulation application.&amp;nbsp; I recently ran the simulations against about 6 years of stock history (almost 10 million rows) in order to simulate different entry/exit trading strategies.&amp;nbsp; This generated nearly 2 million orders and over 1 million end-of-day portfolio rows.&amp;nbsp; What was interesting was that at the beginning of the simulation before there were any rows in my portfolio Orders table, the buy/sell procedures were running very fast.&amp;nbsp; They didn’t start slowing down until over 1 million rows, and even then they weren’t too bad, considering the volume of data.&amp;nbsp; You can see this from the attached chart.&amp;nbsp; At that time, the indexes were undoubtedly not pretty as some of them were being split a lot due to the various combinations of fields that had to be indexed in order to close out positions, evaluate trading effectiveness, etc.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;If my routine was simply to generate a couple of million of rows each night, I could just add a post-processing step to rebuild all of the fragmented indexes, then I would have left well enough alone.&amp;nbsp;&amp;nbsp; (for a great tool to automate this, see &lt;A title=http://blog.sqlauthority.com/2008/03/04/sql-server-2005-a-simple-way-to-defragment-all-indexes-in-a-database-that-is-fragmented-above-a-declared-threshold/ href="http://blog.sqlauthority.com/2008/03/04/sql-server-2005-a-simple-way-to-defragment-all-indexes-in-a-database-that-is-fragmented-above-a-declared-threshold/" mce_href="http://blog.sqlauthority.com/2008/03/04/sql-server-2005-a-simple-way-to-defragment-all-indexes-in-a-database-that-is-fragmented-above-a-declared-threshold/"&gt;http://blog.sqlauthority.com/2008/03/04/sql-server-2005-a-simple-way-to-defragment-all-indexes-in-a-database-that-is-fragmented-above-a-declared-threshold/&lt;/A&gt; – I copied and pasted this into a SQL job step I run nightly and I don’t worry any more about index fragmentation and it runs a lot faster than using the built-in SQL index maintenance tools, because it only does what it needs to).&amp;nbsp; In any case, turns out that what I really want to do is just update the data daily with a few new simulations and append to the existing one.&amp;nbsp; For the append, the query plan was still good, since I still need to create a few thousand orders and update a few thousand (fill the buy orders, close the sell orders).&amp;nbsp; But, for just adding a new simulation that goes back 7 years, it was taking inordinately long given the amount of data.&amp;nbsp; You can see from the below chart, that even though only a few or in some cases no records were updated, the buy and sell procedures were taking almost as long as when 2 – 3,000 rows were being updated.&lt;/P&gt;
&lt;TABLE style="WIDTH: 331pt; BORDER-COLLAPSE: collapse" border=0 cellSpacing=0 cellPadding=0 width=440&gt;
&lt;COLGROUP&gt;
&lt;COL style="WIDTH: 57pt; mso-width-source: userset; mso-width-alt: 2779" width=76&gt;
&lt;COL style="WIDTH: 65pt; mso-width-source: userset; mso-width-alt: 3145" width=86&gt;
&lt;COL style="WIDTH: 82pt; mso-width-source: userset; mso-width-alt: 3986" width=109&gt;
&lt;COL style="WIDTH: 70pt; mso-width-source: userset; mso-width-alt: 3401" width=93&gt;
&lt;COL style="WIDTH: 57pt; mso-width-source: userset; mso-width-alt: 2779" width=76&gt;&lt;/COLGROUP&gt;
&lt;TBODY&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="WIDTH: 57pt; FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl66 height=20 width=76 class="xl66"&gt;&lt;/TD&gt;
&lt;TD style="WIDTH: 65pt; FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl67 width=86 class="xl67"&gt;&lt;/TD&gt;
&lt;TD style="WIDTH: 82pt; FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" width=109&gt;&lt;/TD&gt;
&lt;TD style="WIDTH: 70pt; FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl67 width=93 class="xl67"&gt;&lt;/TD&gt;
&lt;TD style="WIDTH: 57pt; FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" width=76&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl66 height=20 class="xl66"&gt;&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none; mso-ignore: colspan" class=xl67 colSpan=2 class="xl67"&gt;Main simulation&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none; mso-ignore: colspan" class=xl67 colSpan=2 class="xl67"&gt;1 Portfolio Simulation&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl68 height=20 class="xl68"&gt;MarketDate&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;ElapsedTime&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;Rows&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;ElapsedTime&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;Rows&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl65 height=20 align=right class="xl65"&gt;8/5/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;2466&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;70&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl65 height=20 align=right class="xl65"&gt;8/6/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;2895&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;36&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl65 height=20 align=right class="xl65"&gt;8/7/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;2681&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;206&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl65 height=20 align=right class="xl65"&gt;8/10/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;1603&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;22&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl65 height=20 align=right class="xl65"&gt;8/11/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;2820&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;12&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;91&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl65 height=20 align=right class="xl65"&gt;8/12/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;13&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;1925&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;29&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;So, the question is, how can I still keep the batch-oriented performance optimized to process thousands of buy/sell orders all at once, while also getting good-turn around when we have a handful of orders?&amp;nbsp; Enter the query hint “OPTION RECOMPILE”.&amp;nbsp; Most of the time, using this hint doesn’t make sense, because it defeats one of the great features of SQL Server for auto-parameterizing execution.&amp;nbsp; Auto-parameterization is another complex topic covered in the earlier links I listed, but basically allows SQL to look at similar queries, particularly when they are done in a stored procedure, and come up with a reusable plan.&amp;nbsp; It does this based on the parameters for the execution.&amp;nbsp; This works great if you’re calling a stored procedure repeatedly at short intervals, since it saves the recompilation step.&amp;nbsp; However, in my case, my process is mainly batch, I am only calling my stored procedures once per market date for all of the simulations.&amp;nbsp; With the exception of 1 row-oriented procedure, I basically simulate an entire' days worth of stock market activity in 7 stored procedures, so in my scenario I don’t care about the time being saved on the recompile.&amp;nbsp; By using OPTION RECOMPILE, SQL will look at the stored procedure each time and look at all of the parameters and their values and then make the right decisions.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Lets take a look at the stored procedure.&amp;nbsp; You can see for example in my stored procedure where dynamic evaluation of the parameter values would help.&amp;nbsp; If for example, I am calling for just a single portfolio, that makes for an entirely different plan than when there are hundreds of portfolios.&amp;nbsp; One approach involves scanning through the orders by key to look for qualifying orders and then matching back to the portfolios while the other approach involves looking up a single portfolio and evaluating only the orders for that portfolio.&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;CREATE&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;PROCEDURE&lt;/SPAN&gt; [Olap].[ProcessSellOrders]
    @MarketDate &lt;SPAN class=kwrd&gt;DATE&lt;/SPAN&gt;, @&lt;SPAN class=kwrd&gt;RowCount&lt;/SPAN&gt; BIGINT &lt;SPAN class=kwrd&gt;OUT&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;AS&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;BEGIN&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;-- SET NOCOUNT ON added to prevent extra result sets from&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;-- interfering with SELECT statements.&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;SET&lt;/SPAN&gt; NOCOUNT &lt;SPAN class=kwrd&gt;ON&lt;/SPAN&gt;;
    &lt;SPAN class=kwrd&gt;SET&lt;/SPAN&gt; XACT_ABORT &lt;SPAN class=kwrd&gt;ON&lt;/SPAN&gt;;
    &lt;SPAN class=rem&gt;-- Assume bollinger history technique for now&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;-- Similar logic as Process Buys, except reverse the trading methods with same&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;-- logic for daily high/daily low, but update Close date, limit instead of Open date, &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;-- and check stop limits &lt;/SPAN&gt;
    
    &lt;SPAN class=rem&gt;-- We don't know if the low or high hit first, so to be on the safe side, we assume&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;-- that the worse happened and so check the stop limit first &lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;UPDATE&lt;/SPAN&gt; [Olap].[PortfolioOrder]
        &lt;SPAN class=kwrd&gt;SET&lt;/SPAN&gt; FilledPriceClose = dbo.udf_CalculateFillPrice
            (PortfolioOrder.StoplimitPrice
            ,PortfolioOrder.LimitPriceClose
            ,ed.PriceAtOpen
            ,ed.DailyLow
            ,ed.DailyHigh
            ,PortfolioOrder.TradingMethod),
        CloseDate = @MarketDate
    &lt;SPAN class=kwrd&gt;FROM&lt;/SPAN&gt;    olap.Portfolio pf, 
            dbo.view_EquityDetails_Brief ed
    &lt;SPAN class=kwrd&gt;WHERE&lt;/SPAN&gt;    (pf.StartDate &amp;lt;= @MarketDate &lt;SPAN class=kwrd&gt;and&lt;/SPAN&gt; (pf.EndDate &amp;gt;= @MarketDate &lt;SPAN class=kwrd&gt;or&lt;/SPAN&gt; pf.EndDate &lt;SPAN class=kwrd&gt;IS&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;NULL&lt;/SPAN&gt;))
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; (pf.LastUpdateDate &amp;lt; @MarketDate &lt;SPAN class=kwrd&gt;or&lt;/SPAN&gt; pf.LastUpdateDate &lt;SPAN class=kwrd&gt;is&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;)
        &lt;SPAN class=rem&gt;-- Last Update Date not set until EOD&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.PortfolioId = pf.PortfolioId
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; ed.MarketDate = @MarketDate
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; ed.TradingSymbol = PortfolioOrder.TradingSymbol    
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.OpenDate &amp;lt;= @MarketDate 
        &lt;SPAN class=rem&gt;-- See if valid for day trade - An equity is valid for day trade if it was bought using the&lt;/SPAN&gt;
        &lt;SPAN class=rem&gt;-- opening price.&lt;/SPAN&gt;
        &lt;SPAN class=rem&gt;-- Don't get confused by new orders for next market date&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.CreateDate &amp;lt; @MarketDate 
        &lt;SPAN class=rem&gt;-- Redundant since earlier than OpenDate, but include so that optimal index can be used&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.OrderStatus = 2
        &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; (       (ed.PriceAtOpen &amp;gt;= PortfolioOrder.StopLimitPrice &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'S'&lt;/SPAN&gt; )&lt;BR&gt;&lt;SPAN class=rem&gt;-- Stop price hit at open&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (ed.PriceAtOpen &amp;lt;= PortfolioOrder.LimitPriceClose &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'S'&lt;/SPAN&gt; ) &lt;BR&gt;&lt;SPAN class=rem&gt;-- Limit price hit at open&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (ed.DailyHigh &amp;gt;= PortfolioOrder.StopLimitPrice &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'S'&lt;/SPAN&gt; )&lt;BR&gt;&lt;SPAN class=rem&gt;-- Stop price hit during the day&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (ed.DailyLow &amp;lt;= PortfolioOrder.LimitPriceClose &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'S'&lt;/SPAN&gt; ) &lt;BR&gt;&lt;SPAN class=rem&gt;-- Limit price hit during the day&lt;/SPAN&gt;
            
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (ed.PriceAtOpen &amp;lt;= PortfolioOrder.StopLimitPrice &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'L'&lt;/SPAN&gt;)&lt;BR&gt;&lt;SPAN class=rem&gt;-- Stop price hit at open&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (ed.PriceAtOpen &amp;gt;= PortfolioOrder.LimitPriceClose &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'L'&lt;/SPAN&gt;) &lt;BR&gt;&lt;SPAN class=rem&gt;-- Limit price hit at open&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (ed.DailyLow &amp;lt;= PortfolioOrder.StopLimitPrice &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'L'&lt;/SPAN&gt;)&lt;BR&gt;&lt;SPAN class=rem&gt;-- Stop price hit during the day&lt;/SPAN&gt;
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (ed.DailyHigh &amp;gt;= PortfolioOrder.LimitPriceClose &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.TradingMethod = &lt;SPAN class=str&gt;'L'&lt;/SPAN&gt;)&lt;BR&gt; &lt;SPAN class=rem&gt;-- Limit price hit during the day&lt;/SPAN&gt;
            )

            &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; (    (PortfolioOrder.IsValidForDayTrade = 1 &lt;SPAN class=kwrd&gt;AND&lt;/SPAN&gt; PortfolioOrder.OpenDate = @MarketDate)
                &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; (PortfolioOrder.OpenDate &amp;lt; @MarketDate)
            )


    &lt;SPAN class=kwrd&gt;SET&lt;/SPAN&gt; @&lt;SPAN class=kwrd&gt;RowCount&lt;/SPAN&gt; = &lt;SPAN class=preproc&gt;@@ROWCOUNT&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;END&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_2.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_2.png"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_thumb.png" width=244 height=235 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_thumb.png"&gt;&lt;/A&gt; &lt;A href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_4.png" mce_href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_4.png"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_thumb_1.png" width=244 height=136 mce_src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/SomeUsesforQueryHints_1277A/image_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;SQL 20008 provides much more flexibility in how to supply query hints.&amp;nbsp; For example, in the above stored procedure, we can just put the keywords OPTION (RECOMPILE) at the end of the query rather than using the legacy RECOMPILE option for the whole stored procedure.&amp;nbsp; If there were multiple queries, we could put different query hints or no query hints with each query, so there is a great improvement in granularity for performing this kind of tweaking in SQL 2008.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here’s the difference in performance after changing to using the RECOMPILE hint.&amp;nbsp; Times are rounded to the nearest second, so 0 means less than .5 seconds.&amp;nbsp; Here you can see the difference in the query plan when I am only calling for a single portfolio versus the case where all of the portfolios are being processed.&amp;nbsp; OPTION RECOMPILE is particularly useful when there is a lot of variation in the parameters value that ultimately determine the search arguments and predicates for scenarios where one index may make much more sense than another index depending on the search criteria.&lt;/P&gt;
&lt;TABLE style="WIDTH: 453pt; BORDER-COLLAPSE: collapse" border=0 cellSpacing=0 cellPadding=0 width=602&gt;
&lt;COLGROUP&gt;
&lt;COL style="WIDTH: 57pt; mso-width-source: userset; mso-width-alt: 2779" width=76&gt;
&lt;COL style="WIDTH: 65pt; mso-width-source: userset; mso-width-alt: 3145" width=86&gt;
&lt;COL style="WIDTH: 82pt; mso-width-source: userset; mso-width-alt: 3986" width=109&gt;
&lt;COL style="WIDTH: 70pt; mso-width-source: userset; mso-width-alt: 3401" width=93&gt;
&lt;COL style="WIDTH: 57pt; mso-width-source: userset; mso-width-alt: 2779" width=76&gt;
&lt;COL style="WIDTH: 65pt; mso-width-source: userset; mso-width-alt: 3145" width=86&gt;
&lt;COL style="WIDTH: 57pt; mso-width-source: userset; mso-width-alt: 2779" width=76&gt;&lt;/COLGROUP&gt;
&lt;TBODY&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="WIDTH: 57pt; FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl66 height=20 width=76 class="xl66"&gt;&lt;/TD&gt;
&lt;TD style="WIDTH: 147pt; FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none; mso-ignore: colspan" class=xl67 width=195 colSpan=2 class="xl67"&gt;Main simulation&lt;/TD&gt;
&lt;TD style="WIDTH: 127pt; FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none; mso-ignore: colspan" class=xl67 width=169 colSpan=2 class="xl67"&gt;1 Portfolio Simulation&lt;/TD&gt;
&lt;TD style="WIDTH: 122pt; FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none; mso-ignore: colspan" class=xl67 width=162 colSpan=2 class="xl67"&gt;After Option Recompile&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl68 height=20 class="xl68"&gt;MarketDate&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;ElapsedTime&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;Rows&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;ElapsedTime&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;Rows&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;ElapsedTime&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 700; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl69 class="xl69"&gt;Rows&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl65 height=20 align=right class="xl65"&gt;8/5/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;2466&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;70&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;1&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;70&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl65 height=20 align=right class="xl65"&gt;8/6/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;2895&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;36&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;0&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;36&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl65 height=20 align=right class="xl65"&gt;8/7/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;2681&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;206&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;0&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;206&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl65 height=20 align=right class="xl65"&gt;8/10/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;1603&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;22&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;0&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;22&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" class=xl65 height=20 align=right class="xl65"&gt;8/11/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;2820&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;12&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;91&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;0&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #4f81bd; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #4f81bd none" align=right&gt;91&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="HEIGHT: 15pt" height=20&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; HEIGHT: 15pt; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" class=xl65 height=20 align=right class="xl65"&gt;8/12/2009&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;13&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;1925&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;11&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;29&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;0&lt;/TD&gt;
&lt;TD style="FONT-FAMILY: calibri; BACKGROUND: #376091; COLOR: white; FONT-SIZE: 11pt; FONT-WEIGHT: 400; TEXT-DECORATION: none; text-underline-style: none; text-line-through: none; mso-pattern: #376091 none" align=right&gt;29&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;P.S: Since I wrote this, I put my indexed view back in and now the sell orders stored procedure even with the main simulation also performs in just a couple of seconds, even with the indexes fragmented.&lt;/P&gt;
&lt;DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b333e1ad-b0b2-44e2-b35e-b68588ccff77 class=wlWriterEditableSmartContent&gt;Technorati Tags: &lt;A href="http://technorati.com/tags/SQL+Server+2008" rel=tag mce_href="http://technorati.com/tags/SQL+Server+2008"&gt;SQL Server 2008&lt;/A&gt;,&lt;A href="http://technorati.com/tags/SQL+Server+Performance" rel=tag mce_href="http://technorati.com/tags/SQL+Server+Performance"&gt;SQL Server Performance&lt;/A&gt;,&lt;A href="http://technorati.com/tags/Query+Hints" rel=tag mce_href="http://technorati.com/tags/Query+Hints"&gt;Query Hints&lt;/A&gt;&lt;/DIV&gt;
&lt;P&gt;For more about query hints, see &lt;A title=http://technet.microsoft.com/en-us/library/ms181714(SQL.90).aspx href="http://technet.microsoft.com/en-us/library/ms181714(SQL.90).aspx" mce_href="http://technet.microsoft.com/en-us/library/ms181714(SQL.90).aspx"&gt;http://technet.microsoft.com/en-us/library/ms181714(SQL.90).aspx&lt;/A&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9869385" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/T-SQL+Tips+and+Tricks/default.aspx">T-SQL Tips and Tricks</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Performance/default.aspx">SQL Performance</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Query+Hints/default.aspx">Query Hints</category></item><item><title>Getting the full exception from .NET</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/04/getting-the-full-exception-from-net.aspx</link><pubDate>Tue, 04 Aug 2009 19:31:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9857233</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9857233.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9857233</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9857233</wfw:comment><description>&lt;p&gt;While we're on the topic of .NET coding, here's another technique.&amp;#160; If you thought my last post was short, here's an even shorter one...&lt;/p&gt;  &lt;p&gt;Ever wanted to make sure you returned an error message with all of the inner exceptions?&amp;#160; I know I've wasted a lot of time trying to debug code that only returned the top level exception, especially if it occurred in production due to an environmental issue that couldn't be repro-ed in dev, and the production environment didn't allow for Visual Studio debugging.&lt;/p&gt;  &lt;p&gt;The below function is a recursive function that calls itself until it has traversed all of the inner exceptions.&amp;#160; It will make sure you always get all of the exceptions delimited by a &amp;quot;/&amp;quot; down to the lowest level.&amp;#160; The deepest level message will be the last one in the string.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; buildExceptionMessage(String message, Exception ex)
        {
            Exception innerException = ex.InnerException;
            message += ex.Message;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (ex.InnerException != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                buildExceptionMessage(message + &lt;span class="str"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;, ex.InnerException);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; message;
        }&lt;/pre&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ed465492-f3c9-4db9-9bfb-af49a5b96a27" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Visual+Studio+.NET" rel="tag"&gt;Visual Studio .NET&lt;/a&gt;&lt;/div&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9857233" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/CodeProject/default.aspx">CodeProject</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Visual+Studio.NET/default.aspx">Visual Studio.NET</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/.NET+Tips+and+Tricks/default.aspx">.NET Tips and Tricks</category></item><item><title>Fun with Enums and a Generic File Date/Time Stamper</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/04/fun-with-enums-and-a-generic-file-date-time-stamper.aspx</link><pubDate>Tue, 04 Aug 2009 19:26:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9857227</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9857227.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9857227</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9857227</wfw:comment><description>&lt;p&gt;Time for a break from SQL stuff for a little .NET.&amp;#160; Have you ever wanted to use the integer value of an ENUM instead of the actual Enum Value?&amp;#160; For example, here is an enum I created to map datetime formats.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;enum&lt;/span&gt; FileDatePrecision
{
    Day = 0, Hour = 2, Minute = 4, Second = 6,  
    Secondsf1 = 7, Secondsf2 = 8, Secondsf3 = 9, 
    Secondsf4 = 10, Secondsf5 = 11, Secondsf6 = 12, 
    Secondsf7 = 13
}&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Never mind the weird names for the fractional second parts, was going to do &amp;quot;Millisecond, Microsecond, etc, but couldn't figure out the names for all of the fractional precisions.&amp;#160; Each &amp;quot;N&amp;quot; value for f is the fractional precision - i.e. f1 means 1/10 of a second, F2 means 1/100, and so on.&lt;/p&gt;

&lt;p&gt;So, why did I create the enums with non-contiguous integer values?&amp;#160; The reason is to accommodate a simple way to generate the format mask.&amp;#160; Here's the code that returns the date time stamp with a couple of overload methods to provide defaults.&amp;#160; It's pretty simple, just use the enum value as the substring length in order to include the characters in the format mask needed to achieve the desired output precision.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; BuildFileDateTimeStamp(DateTime dt, FileDatePrecision precision)
{
    &lt;span class="rem"&gt;// Convert the enum to it's integer representation&lt;/span&gt;
    &lt;span class="kwrd"&gt;int&lt;/span&gt; precisonSequence = (&lt;span class="kwrd"&gt;int&lt;/span&gt;)Enum.Parse(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(FileDatePrecision), precision.ToString());
    &lt;span class="kwrd"&gt;string&lt;/span&gt; formattedTime = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (precisonSequence &amp;gt; 0)
    {
        &lt;span class="rem"&gt;// Format the time based on the level of precision specified in the enum&lt;/span&gt;
        formattedTime = &lt;span class="str"&gt;&amp;quot;_&amp;quot;&lt;/span&gt; + dt.ToString(&lt;span class="str"&gt;&amp;quot;HHmmssfffffff&amp;quot;&lt;/span&gt;).Substring(0,precisonSequence);
    }
    &lt;span class="rem"&gt;//to get the date&lt;/span&gt;
    &lt;span class="kwrd"&gt;string&lt;/span&gt; formattedDate = dt.ToString(&lt;span class="str"&gt;&amp;quot;yyyyMMdd&amp;quot;&lt;/span&gt;);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; formattedDate + formattedTime;
}&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; BuildFileDateTimeStamp(DateTime dt)
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; BuildFileDateTimeStamp(dt, FileDatePrecision.Minute);
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; BuildFileDateTimeStamp()
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; BuildFileDateTimeStamp(DateTime.Now);
}&lt;/pre&gt;

&lt;p&gt;So, to create a filename for example for &amp;quot;StockDownloader_20090803.LOG&amp;quot; for use in a trace writer, I can just do &lt;/p&gt;

&lt;pre class="csharpcode"&gt;TextWriterTraceListener myWriter = &lt;span class="kwrd"&gt;new&lt;/span&gt;
      TextWriterTraceListener(
      System.IO.File.CreateText(&lt;span class="str"&gt;&amp;quot;StockDownloader_&amp;quot;&lt;/span&gt; 
      + Common.Utility.BuildFileDateTimeStamp() + &lt;span class="str"&gt;&amp;quot;.log&amp;quot;&lt;/span&gt;));
    Trace.Listeners.Add(myWriter);&lt;/pre&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2addc073-0b67-4d76-b131-477e014734e5" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Visual+Studio+.NET" rel="tag"&gt;Visual Studio .NET&lt;/a&gt;&lt;/div&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9857227" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/CodeProject/default.aspx">CodeProject</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Visual+Studio.NET/default.aspx">Visual Studio.NET</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/.NET+Tips+and+Tricks/default.aspx">.NET Tips and Tricks</category></item><item><title>A Generic Interval Range Table to Generate Permutations</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/04/a-generic-interval-range-table-to-generate-permutations.aspx</link><pubDate>Tue, 04 Aug 2009 03:07:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9856639</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9856639.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9856639</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9856639</wfw:comment><description>&lt;p&gt;In earlier post (&lt;a title="http://blogs.msdn.com/microsoftbob/archive/2009/07/06/generating-a-list-of-calendar-dates.aspx" href="http://blogs.msdn.com/microsoftbob/archive/2009/07/06/generating-a-list-of-calendar-dates.aspx"&gt;http://blogs.msdn.com/microsoftbob/archive/2009/07/06/generating-a-list-of-calendar-dates.aspx&lt;/a&gt;), I provided an example of how to use a UDF that returns calendar days in order to generate data from a table valued function.&amp;#160; Today, I expand on this using a similar technique, but based on an interval range table which can be used generically.&amp;#160; If you've been following my blog, then you're aware of my interest in simulations.&amp;#160; The technique that I am going over today is great for this scenario, as we can generate all sorts of combinations of parameters into a result set which can then be joined to our sources to generate the desired combinations of data to test.&lt;/p&gt;  &lt;p&gt;To start with, we create a table for storing information about the ranges and how we would like to generate them:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Olap].[IntervalRange](
    [RangeId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [RangeStart] [smallmoney] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [RangeEnd] [smallmoney] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [RangeType] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](5) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [RangeInterval] [smallmoney] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [RangeGrade] [tinyint] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
 &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_Range] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
(
    [RangeId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;
)) &lt;span class="kwrd"&gt;ON&lt;/span&gt; [&lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt;]&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Below is some sample data.&amp;#160; The RangeStart indicates the first number in the range, the range end indicates the ending value and the range interval determines the increment to use when generating the range.&lt;/p&gt;

&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="64"&gt;RangeId&lt;/td&gt;

      &lt;td width="64"&gt;RangeStart&lt;/td&gt;

      &lt;td width="64"&gt;RangeEnd&lt;/td&gt;

      &lt;td width="64"&gt;RangeType&lt;/td&gt;

      &lt;td width="64"&gt;RangeInterval&lt;/td&gt;

      &lt;td width="64"&gt;RangeGrade&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;

      &lt;td&gt;-6&lt;/td&gt;

      &lt;td&gt;21&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;3&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;

      &lt;td&gt;40&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;6&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;

      &lt;td&gt;10&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;7&lt;/td&gt;

      &lt;td&gt;13&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;3&lt;/td&gt;

      &lt;td&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="64"&gt;16&lt;/td&gt;

      &lt;td width="64"&gt;1&lt;/td&gt;

      &lt;td width="64"&gt;5&lt;/td&gt;

      &lt;td width="64"&gt;EPS&lt;/td&gt;

      &lt;td width="64"&gt;1&lt;/td&gt;

      &lt;td width="64"&gt;NULL&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;From this, we can easily join the data and then insert into a table that contains the combinations to generate a list of strategies which include the EPS Grade, the Exit divisor, and the entry threshold:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [Olap].[GenerateStrategies]
    &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; Olap.Strategy ( EPSGrade, EntryThreshold, ExitDivisor)
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; eps.&lt;span class="kwrd"&gt;Interval&lt;/span&gt; &lt;span class="kwrd"&gt;as&lt;/span&gt; EPSGrade, &lt;br /&gt;e.&lt;span class="kwrd"&gt;Interval&lt;/span&gt; &lt;span class="kwrd"&gt;as&lt;/span&gt; EntryThreshold, &lt;br /&gt;x.&lt;span class="kwrd"&gt;Interval&lt;/span&gt; &lt;span class="kwrd"&gt;as&lt;/span&gt; ExitDivisor 
    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Olap.view_RangeIntervals eps 
        &lt;span class="kwrd"&gt;CROSS&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Olap.view_RangeIntervals e 
        &lt;span class="kwrd"&gt;CROSS&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Olap.view_RangeIntervals x 
    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; eps.RangeType = &lt;span class="str"&gt;'EPS'&lt;/span&gt; 
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; e.RangeType = &lt;span class="str"&gt;'ENTRY'&lt;/span&gt; 
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; x.RangeType = &lt;span class="str"&gt;'EXIT'&lt;/span&gt;
    &lt;span class="kwrd"&gt;AND&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;EXISTS&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 0 &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Olap.Strategy
                    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; e.&lt;span class="kwrd"&gt;Interval&lt;/span&gt; = EntryThreshold
                        &lt;span class="kwrd"&gt;AND&lt;/span&gt; x.&lt;span class="kwrd"&gt;Interval&lt;/span&gt; = ExitDivisor
                        &lt;span class="kwrd"&gt;AND&lt;/span&gt; eps.&lt;span class="kwrd"&gt;Interval&lt;/span&gt; = EPSGrade)
    END&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Here are the first few results and the last few results of the cross joins of the parameters.&amp;#160; I won't show all of them because it turns out that the select query above actually generates 700 rows in total.&amp;#160; This is because there are 5 EPS intervals in total, 14 Entry intervals, and 10 Exit intervals, which works out to 5 X 14 X 10 or 700.&amp;#160; So, we basically generate 700 different combinations from our 5 row interval range blueprint data.&lt;/p&gt;

&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="75"&gt;RangeType&lt;/td&gt;

      &lt;td width="64"&gt;Interval&lt;/td&gt;

      &lt;td width="64"&gt;RangeType&lt;/td&gt;

      &lt;td width="64"&gt;Interval&lt;/td&gt;

      &lt;td width="64"&gt;RangeType&lt;/td&gt;

      &lt;td width="64"&gt;Interval&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;-6&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;-3&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;0&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;3&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;6&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;9&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;12&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;15&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;18&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;21&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;30&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;35&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;40&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;-6&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;-3&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;0&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;3&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;1&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;6&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;...&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;...&lt;/td&gt;

      &lt;td&gt;...&lt;/td&gt;

      &lt;td&gt;...&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="75"&gt;EPS&lt;/td&gt;

      &lt;td width="64"&gt;5&lt;/td&gt;

      &lt;td width="64"&gt;ENTRY&lt;/td&gt;

      &lt;td width="64"&gt;35&lt;/td&gt;

      &lt;td width="64"&gt;EXIT&lt;/td&gt;

      &lt;td width="64"&gt;22&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;40&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;22&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;-6&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;-3&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;0&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;3&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;6&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;9&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;12&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;15&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;18&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;21&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;30&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;35&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;EPS&lt;/td&gt;

      &lt;td&gt;5&lt;/td&gt;

      &lt;td&gt;ENTRY&lt;/td&gt;

      &lt;td&gt;40&lt;/td&gt;

      &lt;td&gt;EXIT&lt;/td&gt;

      &lt;td&gt;25&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;There you have it, a whole bunch of permutations from just a small amount of definition data.&amp;#160; One caveat is that you may end up with some combinations that are at an extreme and don't make sense for your simulation.&amp;#160; To get around this issue, I use an exclusion table that gets generated based on ineffective strategy combinations.&amp;#160; This then gets fed back into the process such that strategy permutations are linked via a left outer join, such that those which are found in the exclusion list do not get included in the generation routine.&amp;#160; &lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e40bdb4a-548f-4958-94ef-2aca4f5dd739" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Simulation" rel="tag"&gt;Simulation&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+UDF" rel="tag"&gt;SQL UDF&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Table+Value+Function" rel="tag"&gt;Table Value Function&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server+2008" rel="tag"&gt;SQL Server 2008&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9856639" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/T-SQL+Tips+and+Tricks/default.aspx">T-SQL Tips and Tricks</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/CodeProject/default.aspx">CodeProject</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Simulation/default.aspx">Simulation</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+UDF/default.aspx">SQL UDF</category></item><item><title>Using NTILE with Cross Reference Values to Create Dimensions</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/08/04/using-ntile-with-cross-reference-values-to-create-dimensions.aspx</link><pubDate>Tue, 04 Aug 2009 02:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9856624</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9856624.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9856624</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9856624</wfw:comment><description>&lt;p&gt;I confess&amp;#160; lack of depth in SQL Analysis Services (SSAS).&amp;#160; I've read quite a bit about the capabilities including data mining, and played with a couple of the wizards, but just haven't had time to immerse deeply into end-to-end scenarios.&amp;#160; Based on that, I'm writing this post with a big disclaimer - You might be able to do some of what is in this post easier with Analysis Services - I don't really know yet.&amp;#160; You'll have to forgive me for ignorance here.&lt;/p&gt;  &lt;p&gt;Although SQL Analysis Services provides a lot of capability, it does seem that you will get better results if you &amp;quot;prep&amp;quot; the data before-hand in SQL, particularly the sources for the dimensions.&amp;#160; Therefore this post may be useful even if you are highly leveraging SSAS.&amp;#160;&amp;#160; In my scenario, it would be useful to reduce the range of values associated with the variables, due to the sheer size of the data sets, the multiplicative effect with combining different variable permutations,&amp;#160; and for simplicity of the analysis .&amp;#160; Basically, this means to summarize ranges of values into different groups and then analyze correlations of the grouped values of the variables - hence the &amp;quot;NTILE&amp;quot; title of this article.&amp;#160; Think of it as assigning grades rather than point scores, so you can identify the &amp;quot;A&amp;quot;,&amp;quot;B&amp;quot; etc students without getting immersed in the point distinctions.&amp;#160; Once you have the students grouped by grade levels, then you can much easier do correlative analysis - i.e., how much time do &amp;quot;A&amp;quot; students spend on homework versus &amp;quot;&amp;quot;C&amp;quot; students, as opposed to analyzing the homework correlation with students with 93/100 do compared to 74/100 point-scaled graded students.&lt;/p&gt;  &lt;p&gt;First a little bit about the application - My requirements include the ability to correlate various factors about an equity - it's earnings per share (EPS), Price-earnings growth (PEG), Sector, period of performance etc. to indicate if any of these have to do with profitability of a stock purchased at a particular time and when it should be sold.&lt;/p&gt;  &lt;p&gt;Hopefully, that provides enough background so some of this will make some sense.&lt;/p&gt;  &lt;p&gt;So for my scenario, some what-if questions: Do certain sectors or industries perform better during certain periods in relation to other stocks?&amp;#160; How does the EPS affect trading profitability?&amp;#160; What about market capitalization?&amp;#160; Do the combination of these have an impact?&amp;#160; For example, is it more profitable to invest in stocks with small capitalization in some industries during certain times of the year?&lt;/p&gt;  &lt;p&gt;Essentially, it would be nice to be able to take all of these factors, generate permutations, and then analyze simulations of stock trades for a period of time to see if any combinations are effective to predict how successful a strategy will perform.&amp;#160; Now, if we were to just take all of the combinations of these, the multiplicative effect of the permutations would be unmanageable and more than the &amp;quot;fact&amp;quot; data since each the precision on many of these values is large enough to generate hundreds if not thousands of distinct values.&amp;#160; &amp;quot;Permutating&amp;quot; all of this together produces a lot of interesting but meaningless data.&lt;/p&gt;  &lt;p&gt;The NTILE feature allows assigning a group based on an interval to a set of data.&amp;#160; One of the variables I want to NTILE is Earnings-Per-Share EPS).&amp;#160; Another is market capitalization.&amp;#160; Another could be Sector.&amp;#160; And finally, the period.&amp;#160; By NTILE, I mean grouping into categories, so for example, every stock would fall into just 1 of 5 different tiles or ratings for EPS, or for market cap, etc.&amp;#160; You can see how by reducing these into groupings, we greatly simplify the analysis and reduce the number of permutations while still having enough granularity to differentiate the groupings.&amp;#160; We just have to figure out a way to map the original &amp;quot;fact&amp;quot; data values to their groupings (grades).&amp;#160; Once we have the mapping, we can join the tiled dimensional data back to the fact data.&amp;#160; Yes, I know this is sounding more like a SSAS scenario, but remember I already gave my disclaimer...&amp;#160; I'd welcome responses back from the BI experts on how to approach this scenario using SSAS.&lt;/p&gt;  &lt;p&gt;So, here are some steps to accomplishing this:&lt;/p&gt;  &lt;p&gt;1) Use computed fields to round the fact data into more discrete values, particularly if the original values are not precise, such as floating point.&amp;#160; For example, if we are only need 5 tiles, we probably don't need to map down to the .01 decimal precision. If we instead round down to just the .1 value, our tiling should still be fairly accurate.&amp;#160; This reduces the amount of discrete values in the fact data that need to be tiled and reduces the size of the mapping table.&amp;#160; Below is an example of an Equity Information table with the computed rounded fields&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [dbo].[EquityInfo](
    [TradingSymbol] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](25) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [Description] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](50) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [IndustryId] [&lt;span class="kwrd"&gt;smallint&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [SectorId] [&lt;span class="kwrd"&gt;smallint&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [Shares] [bigint] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [PERatio] [&lt;span class="kwrd"&gt;float&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [EPS] [&lt;span class="kwrd"&gt;float&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [DivYield] [&lt;span class="kwrd"&gt;float&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [DivPerShare] [&lt;span class="kwrd"&gt;float&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [PEG] [&lt;span class="kwrd"&gt;float&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [PriceToSalesRatio] [&lt;span class="kwrd"&gt;float&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [PriceToBookRatio] [&lt;span class="kwrd"&gt;float&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [ExchangeName] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](10) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [EnabledFlag] [&lt;span class="kwrd"&gt;bit&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [DateUpdated] [&lt;span class="kwrd"&gt;date&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [DateCreated] [&lt;span class="kwrd"&gt;date&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [SampleName] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](50) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [TotalBookValue]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; (&lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="kwrd"&gt;when&lt;/span&gt; [PriceToBookRatio]&amp;gt;(0) &lt;span class="kwrd"&gt;AND&lt;/span&gt; [Shares]&amp;gt;(0) &lt;br /&gt;&lt;span class="kwrd"&gt;then&lt;/span&gt; [Shares]/[PriceToBookRatio]  &lt;span class="kwrd"&gt;end&lt;/span&gt;),
    [TotalSalesValue]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; (&lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="kwrd"&gt;when&lt;/span&gt; [PriceToSalesRatio]&amp;gt;(0) &lt;span class="kwrd"&gt;AND&lt;/span&gt; [Shares]&amp;gt;(0) &lt;br /&gt;&lt;span class="kwrd"&gt;then&lt;/span&gt; [Shares]/[PriceToSalesRatio]  &lt;span class="kwrd"&gt;end&lt;/span&gt;),
    [PEG_Rounded]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; (&lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;([smallmoney],ROUND([PEG],1))) &lt;br /&gt;PERSISTED,
    [EPS_Rounded]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; (&lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;([smallmoney],ROUND([EPS],1))) &lt;br /&gt;PERSISTED,
    [PE_Rounded]  &lt;span class="kwrd"&gt;AS&lt;/span&gt;  (&lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;([smallmoney],ROUND([PERatio],1))) &lt;br /&gt;PERSISTED,
    [PTB_Rounded]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; (&lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;([smallmoney],ROUND([PriceToBookRatio],1))) &lt;br /&gt;PERSISTED,
    [PTS_Rounded]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; (&lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;([smallmoney],ROUND([PriceToSalesRatio],1))) &lt;br /&gt;PERSISTED,
    [Shortable] [&lt;span class="kwrd"&gt;bit&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [HistoryReloadRequired] [&lt;span class="kwrd"&gt;bit&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [HistoryReloadedDateTime] [datetime] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
 &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_EquityInfo] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
(
    [TradingSymbol] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;
))&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;2) Create a view that tiles the values for each of the dimensions of interest.&amp;#160; For example, for EPS, we would have the following view:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;VIEW&lt;/span&gt; [Olap].[Vdim_EPS_Tiled]
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;     NTILE(5) &lt;span class="kwrd"&gt;OVER&lt;/span&gt; (&lt;span class="kwrd"&gt;Order&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; EPS_Rounded) &lt;span class="kwrd"&gt;as&lt;/span&gt; EPS_Tile, EPS_Rounded
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;         dbo.EquityInfo
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; EPS_Rounded &lt;span class="kwrd"&gt;Is&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;3) Generate a table from the view to contain cross-reference the tiles back to the source fact data.&amp;#160; The table can be generated through a SELECT INTO and then maintained via a MERGE after we add a primary key.&amp;#160; We need to use Select DISTINCT because our first view will contain duplicate EPS_Rounded values.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; distinct * &lt;span class="kwrd"&gt;into&lt;/span&gt; olap.tdim_EPS_Tiled &lt;span class="kwrd"&gt;from&lt;/span&gt; Olap.vdim_EPS_Tiled;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;GO&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; Olap.tdim_EPS_Tiled &lt;span class="kwrd"&gt;ADD&lt;/span&gt; &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt;
    PK_tdim_EPS_Tiled &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
    (EPS_Rounded) &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;GO&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; olap.Update_tdim_EPS_Tiled
&lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
  MERGE &lt;span class="kwrd"&gt;INTO&lt;/span&gt; olap.tdim_EPS_Tiled &lt;span class="kwrd"&gt;AS&lt;/span&gt; T
  &lt;span class="kwrd"&gt;USING&lt;/span&gt; olap.vdim_eps_Tiled &lt;span class="kwrd"&gt;AS&lt;/span&gt; S
    &lt;span class="kwrd"&gt;ON&lt;/span&gt; S.EPS_Rounded = T.EPS_Rounded
  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; MATCHED 
    &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt;
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; EPS_Tile = S.EPS_Tile
  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; MATCHED &lt;span class="kwrd"&gt;BY&lt;/span&gt; TARGET
    &lt;span class="kwrd"&gt;THEN&lt;/span&gt; INSERT
        (EPS_Tile, EPS_Rounded)
        &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;
        (S.EPS_Tile, S.EPS_Rounded)
  &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; MATCHED &lt;span class="kwrd"&gt;BY&lt;/span&gt; SOURCE
    &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;DELETE&lt;/span&gt;; &lt;span class="rem"&gt;-- Might not want to do this if there is history involved&lt;/span&gt;
END&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Now, whenever I want to analyze performance of an equity related to a simulation, I can easily join to the tdim_EPS_Tiled table on the EPS_Rounded in order to derive the tile.&amp;#160; I can then group these, average the profitability from the simulations and evaluate the degree of correlation.&amp;#160; This should work well with a cube in SSAS as well to allow correlation and predictive data mining.&amp;#160; I'll be trying that out as soon as I get through the SSAS tutorial.&lt;/p&gt;

&lt;p&gt;The below diagram illustrates the process flow including the automation aspect.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/a39407336c1c_F031/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/a39407336c1c_F031/image_thumb.png" width="228" height="244" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In summary: &lt;/p&gt;

&lt;p&gt;First we reduce the number of values to map, so that instead of mapping the entire universe, we map a rounded representation.&amp;#160; We also store it as a precise data type (not floating).&amp;#160; This makes our cross-reference tables smaller.&amp;#160; This introduces some complexity when we want to map from the fact data back, but this is simply remedied by creating computed fields on the fact data that map back to the source.&lt;/p&gt;

&lt;p&gt;Next, we create &amp;quot;Ntile&amp;quot; views of the grouped data.&amp;#160; We can now join back from our source data to find the grade that a particular equity is associated with.&amp;#160; This allows us to do iterative simulation.&amp;#160; By iterative simulation, I mean taking the results of one pass of simulations as input into a higher layer of simulations.&amp;#160; For example, if my simulations show a positive correlation for a particular EPS grade, then I can create another simulation that filters just on the EPS grade to drill-down and better explore the correlations from that.&amp;#160;&amp;#160; good article about iterative and non-iterative simulation algorithms on this link is &lt;a title="http://www.stat.columbia.edu/~gelman/research/published/itsim_interface.pdf" href="http://www.stat.columbia.edu/~gelman/research/published/itsim_interface.pdf"&gt;http://www.stat.columbia.edu/~gelman/research/published/itsim_interface.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might be wondering why not just use indexed views - I tried that and couldn't get it to work, there are limitations on what you can index when it comes to aggregation and apparently using a function like NTILE is one of them.&lt;/p&gt;

&lt;p&gt;Let's all the time I have for this today.&amp;#160; You might be thinking this is neat, but what about all my &amp;quot;what-if&amp;quot; questions?&amp;#160; How do we query our dimension data and link back to our fact to find the correlations.&amp;#160; I have made some interesting correlation discoveries, but I still have a lot of work to do here.&amp;#160; I guess this is where I really need to start using SSAS because the queries to actually find the correlations become very complex -- Time to get out the manual and go through the tutorials...&amp;#160; Time to start playing with the data mining wizards...&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:89338af0-a58e-49a6-b072-0d583ed78003" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SSAS" rel="tag"&gt;SSAS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Analysis+Services" rel="tag"&gt;SQL Analysis Services&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Data+Warehouse" rel="tag"&gt;Data Warehouse&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Data+Warehousing" rel="tag"&gt;Data Warehousing&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server+2008" rel="tag"&gt;SQL Server 2008&lt;/a&gt;,&lt;a href="http://technorati.com/tags/NTILE" rel="tag"&gt;NTILE&lt;/a&gt;,&lt;a href="http://technorati.com/tags/MERGE" rel="tag"&gt;MERGE&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9856624" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/T-SQL+Tips+and+Tricks/default.aspx">T-SQL Tips and Tricks</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/CodeProject/default.aspx">CodeProject</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008+Analysis+Services/default.aspx">SQL Server 2008 Analysis Services</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SSAS/default.aspx">SSAS</category></item><item><title>Using Persisted Computed Columns in SQL Server Indexes</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/07/10/using-persisted-computed-columns-in-sql-server-indexes.aspx</link><pubDate>Fri, 10 Jul 2009 23:43:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9829065</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9829065.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9829065</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9829065</wfw:comment><description>&lt;p&gt;As part of my research work, I generate thousands of simulations on an almost daily basis for various scenarios.&amp;#160; One of my scenarios involves determining strategies for selecting the most profitable short and long stock entry/exit positions.&amp;#160; Calculating this involves data mining stock history information, analyzing moving averages of the equities, and correlating parameters associated with the equities to find the the optimal entry and exit position for a given stock.&amp;#160; I've found one way to calculate this is using brute force computational power to simulate the trades over historic time periods and measure the results.&amp;#160; (There probably is an easier way with advanced calculus using derivatives, etc.).&amp;#160;&amp;#160; In order to play out the simulation, I need to track the position of the equity associated with the order - whether there is an order pending, if the position has been opened, or if the position has been closed, or if the order was cancelled.&amp;#160; For example, I need to measure the dollar value of positions as well as cash in the portfolio to tell how much &amp;quot;buying power&amp;quot; remains to purchase additional equities at a given point of time in the simulation.&lt;/p&gt;  &lt;p&gt;I track dates associated with all of the events, so a &amp;quot;normalized&amp;quot; way to do this is simply to look at the date as shown in these views:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;     &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;CREATE&lt;/span&gt; &lt;span style="color: #0000ff"&gt;VIEW&lt;/span&gt; [Simulator].[view_ValidOrders]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;     PortfolioOrderId, PortfolioId, TradingSymbol, CreateDate, OpenDate, UpdateDate, CloseDate, TradingMethod, Shares, LimitPriceOpen, FilledPriceOpen, &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;                       LimitPriceClose, FilledPriceClose, StopLimitPrice&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;         Simulator.PortfolioOrder&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;     (CancelDate &lt;span style="color: #0000ff"&gt;IS&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt;);&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;CREATE&lt;/span&gt; &lt;span style="color: #0000ff"&gt;VIEW&lt;/span&gt; [Simulator].[view_OpenOrders]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;     PortfolioOrderId, PortfolioId, TradingSymbol, CreateDate, OpenDate, UpdateDate, CloseDate, TradingMethod, Shares, LimitPriceOpen, FilledPriceOpen, &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;                       LimitPriceClose, FilledPriceClose, StopLimitPrice&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;         Simulator.view_ValidOrders&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;     ((CloseDate &lt;span style="color: #0000ff"&gt;IS&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;and&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NOT&lt;/span&gt; (OpenDate &lt;span style="color: #0000ff"&gt;IS&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt;));&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;&amp;#160; &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;CREATE&lt;/span&gt; &lt;span style="color: #0000ff"&gt;VIEW&lt;/span&gt; [Simulator].[view_OpenOrders]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;     PortfolioOrderId, PortfolioId, TradingSymbol, CreateDate, OpenDate, UpdateDate, CloseDate, TradingMethod, Shares, LimitPriceOpen, FilledPriceOpen, &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;                       LimitPriceClose, FilledPriceClose, StopLimitPrice&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;         Simulator.view_ValidOrders&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;     ((CloseDate &lt;span style="color: #0000ff"&gt;IS&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;and&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NOT&lt;/span&gt; (OpenDate &lt;span style="color: #0000ff"&gt;IS&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt;));&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I can then index on the cancel-date, open-date, and close-date in combination with other fields to try to optimize the queries.&amp;#160; But, why do this, when you only need a single status since each state is mutually exclusive?&amp;#160; Based on that, we can create a computed field called OrderStatus (we'll come back to the other computed column &amp;quot;Profit&amp;quot; in a moment) that just has the status as in:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Simulator].[PortfolioOrder](
    [PortfolioOrderId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [PortfolioId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [TradingSymbol] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](50) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [OpenDate] [&lt;span class="kwrd"&gt;date&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [CloseDate] [&lt;span class="kwrd"&gt;date&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [CancelDate] [&lt;span class="kwrd"&gt;date&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [TradingMethod] [&lt;span class="kwrd"&gt;char&lt;/span&gt;](1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
&lt;br /&gt;    [Shares] [smallmoney] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL,&lt;br /&gt;&lt;/span&gt;    [FilledPriceOpen] [smallmoney] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [FilledPriceClose] [smallmoney] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
...
    [Profit]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; ([shares]*&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;br /&gt;&lt;span class="kwrd"&gt;when&lt;/span&gt; [TradingMethod]=&lt;span class="str"&gt;'L'&lt;/span&gt; &lt;span class="kwrd"&gt;then&lt;/span&gt; [FilledPriceClose]-[FilledPriceOpen] &lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt; [FilledPriceOpen]-[FilledPriceClose] &lt;span class="kwrd"&gt;end&lt;/span&gt;) PERSISTED,&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;
    &lt;strong&gt;[OrderStatus]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; (&lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;([tinyint],
&lt;span class="kwrd"&gt;case&lt;/span&gt; 
&lt;span class="kwrd"&gt;when&lt;/span&gt; [CancelDate] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;then&lt;/span&gt; (0) 
&lt;span class="kwrd"&gt;when&lt;/span&gt; [CloseDate] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;AND&lt;/span&gt; [OpenDate] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;then&lt;/span&gt; (1) 
&lt;span class="kwrd"&gt;when&lt;/span&gt; [CloseDate] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;AND&lt;/span&gt; [OpenDate] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;then&lt;/span&gt; (2) 
&lt;span class="kwrd"&gt;else&lt;/span&gt; (3) &lt;span class="kwrd"&gt;end&lt;/span&gt;,(0))) &lt;em&gt;PERSISTED&lt;/em&gt;,&lt;/strong&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;...&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;So, how does the computed field help us with performance?&amp;#160; First, I need to make sure the computed field is persisted and the caveat on that is that only deterministic values can be computed.&amp;#160; Not only that, the computed field must be derived directly from columns in the table, rather than other functions that look at other tables.&amp;#160; For example, I have a current value column on my portfolio that is computed based on the value of all of the underlying positions, but that column is not persist-able since it depends on a function that sums the results from the order detail data (I could use an indexed view for this to get around that, but there are quite a few rules and restrictions around indexed views - see my earlier blog on indexed views).&lt;/p&gt;

&lt;p&gt;The second thing to do is to make sure that the storage for the computed field is optimal.&amp;#160; I wouldn't normally use a floating value for example as a persisted field that gets indexed since floating values are approximate.&amp;#160; Also, I want to make sure the computed field uses as little storage as possible, so that my index is as small as possible, thus potentially reducing the number of levels required for a large number of rows.&amp;#160; That is why I use the CONVERT function for the order status - by default, SQL would set this to be an integer field which is 4 bytes, but all I really need is a single byte or TINYINT.&lt;/p&gt;

&lt;p&gt;Note, that I also use the included columns technique to only include what is needed.&amp;#160; I leverage another persisted computed field called profit rather than the all the source fields needed to calculate the profit so that a covering index will work for my queries, thus eliminating the need to do a lookup back to the base table (see the link at end of article for more info on covering indexes).&amp;#160; This keeps the included data small, which also contributes to a smaller size index entry.&lt;/p&gt;

&lt;p&gt;Using the profit field as an include field along with other relevant fields, and then using the order status gives us the following index, which is just right for the types of queries we need to run in order to perform a stock trading simulation.&amp;#160; This allows us to be able to quickly calculate the profit (or loss) and hence current buying power for the portfolio as well as find orders in a given status (such as newly submitted orders with a limit price) that may need to still be opened into a position or open positions that need to be closed to seal a profit.&lt;/p&gt;

&lt;p&gt;&lt;span class="kwrd"&gt;&lt;em&gt;Index for finding profit of closed orders for portfolio using computed fields:&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;NONCLUSTERED&lt;/span&gt; &lt;span class="kwrd"&gt;INDEX&lt;/span&gt; [IX_PortfolioOrder_Status] &lt;span class="kwrd"&gt;ON&lt;/span&gt; [Simulator].[PortfolioOrder] 
(
    [PortfolioId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;, &lt;span class="rem"&gt;-- 4 bytes&lt;/span&gt;
    [OrderStatus] &lt;span class="kwrd"&gt;ASC&lt;/span&gt; &lt;span class="rem"&gt;-- 1 byte&lt;/span&gt;
)
&lt;span class="kwrd"&gt;INCLUDE&lt;/span&gt; ( [Profit]) - 4 bytes&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Total: 9 bytes&lt;/p&gt;

&lt;p&gt;Contrast that with the below index structure that had additional included columns for (Shares, PriceAtClose, PriceAtOpen instead of just Profit) and included the cancel date to filter out invalid orders, or alternatively did not include any of the date fields, but then had to filter after retrieving by PortfolioId.&lt;/p&gt;

&lt;p&gt;&lt;span class="kwrd"&gt;&lt;em&gt;Index for finding profit of closed orders for portfolio without benefit of computed fields:&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;NONCLUSTERED&lt;/span&gt; &lt;span class="kwrd"&gt;INDEX&lt;/span&gt; [IX_PortfolioOrder_Status] &lt;span class="kwrd"&gt;ON&lt;/span&gt; [Simulator].[PortfolioOrder] 
(
    [PortfolioId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;, &lt;span class="rem"&gt;-- 4 bytes&lt;/span&gt;
    [CloseDate] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;&lt;span class="rem"&gt;-- 4 bytes, probably not worth having this as part of index and just incorporate&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- into the include list and filter.&lt;/span&gt;
)
&lt;span class="kwrd"&gt;INCLUDE&lt;/span&gt; ( [FilledPriceAtOpen], [FilledPriceAtClose], [TradingMethod], [Shares]) - 13 bytes&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Total: 21 bytes&lt;/p&gt;

&lt;p&gt;So, how effective is this technique?&amp;#160; I&amp;quot;m sorry I don't have hard numbers before-and-after, but I can honestly tell you that my simulations for this application are running about twice as fast now.&amp;#160; I believe the main reason is that the number of index levels was reduced, because I was at a threshold due to the number of rows in the Portfolio Orders.&amp;#160; Up to a few hundred thousand rows, the performance was similar, however once we cross that number, we require a second index level due to the sheer length of the index when using the .&amp;#160; Each additional level in the index requires another I/O to per row lookup.&amp;#160; &lt;/p&gt;

&lt;p&gt;This brings up another point about indexes and performance.&amp;#160; If you experience an overnight-drop in performance on some queries as more data is added, it's probably because one of your indexes just had to add another level to support the binary tree.&amp;#160; You'll want to understand how SQL stores indexes to get a better insight on this and other ways to mitigate the issue if merely shrinking the size of the supporting columns is not feasible.&amp;#160; Take a look especially at filtered indexing (which we could have used for this scenario, also), where an index can be defined based on horizontal partitioning - i.e. only create this index for rows meeting a specific filter.&lt;/p&gt;

&lt;p&gt;This points out the need to carefully consider the lengths of the columns you are indexing as well as the sizes of the fields you include in your include list (at some point it doesn't make sense if you're including every field, may as well forget the list and do a lookup).&amp;#160; First, do you really need to use the whole column?&amp;#160; If not, you might want to use a computed field to get a substring of what you really need to index.&amp;#160; Second, are you using the right data type?&amp;#160; If you're shamelessly using GUIDs for primary keys, shame on you, you are wasting 4 times the storage space of a single identity (and not only that creating fragmentation because your inserts are happening all over the tree causing page splits).&lt;/p&gt;

&lt;p&gt;I'd like to go deeper into how to calculate number of bytes per row in an index, etc, but don't have time and there are other resources that provide a much better explanation than I can give.&amp;#160; For more information, see the following links:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Computed columns including their use in indexes: &lt;a title="http://www.mssqltips.com/tip.asp?tip=1702" href="http://www.mssqltips.com/tip.asp?tip=1702"&gt;http://www.mssqltips.com/tip.asp?tip=1702&lt;/a&gt; - Has great explanation and example, better than mine.&amp;#160; &lt;/li&gt;

  &lt;li&gt;Covering indexes: &lt;a title="http://msdn.microsoft.com/en-us/library/ms190806.aspx" href="http://msdn.microsoft.com/en-us/library/ms190806.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms190806.aspx&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;Indexing tips: &lt;a title="http://www.sql-server-performance.com/tips/optimizing_indexes_general_p1.aspx" href="http://www.sql-server-performance.com/tips/optimizing_indexes_general_p1.aspx"&gt;http://www.sql-server-performance.com/tips/optimizing_indexes_general_p1.aspx&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;Why not to use GUIDs if you don't have to: &lt;a title="http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx" href="http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx"&gt;http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;SQL Server Storage Engine: &lt;a title="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx" href="http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx"&gt;http://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/25/646865.aspx&lt;/a&gt; - Includes discussion of storage of included columns.&lt;/li&gt;

  &lt;li&gt;SQL Server 2008 Internals: &lt;a title="http://www.microsoft.com/learning/en/us/book.aspx?ID=12967&amp;amp;locale=en-us" href="http://www.microsoft.com/learning/en/us/book.aspx?ID=12967&amp;amp;locale=en-us"&gt;http://www.microsoft.com/learning/en/us/book.aspx?ID=12967&amp;amp;locale=en-us&lt;/a&gt; (Kalen Delaney, Paul S. Randal, Kimberly L. Tripp, Conor Cunningham, Adam Machanic, and Ben Nevarez)&lt;/li&gt;
&lt;/ul&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:17aed158-a5e0-48c8-ac5a-01e8f793a3cc" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SQL+Server" rel="tag"&gt;SQL Server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Performance" rel="tag"&gt;SQL Performance&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server+Indexing" rel="tag"&gt;SQL Server Indexing&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9829065" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2005/default.aspx">SQL Server 2005</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+Performance/default.aspx">SQL Server Performance</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+Indexing/default.aspx">SQL Server Indexing</category></item><item><title>Auto-Generating Pivot Views</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/07/10/auto-generating-pivot-views.aspx</link><pubDate>Fri, 10 Jul 2009 21:22:06 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9828953</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9828953.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9828953</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9828953</wfw:comment><description>&lt;p&gt;Coming back from the Sci-Fi world of AI, etc to some real world scenarios...&amp;#160; Earlier I posted a generic stored procedure that automatically unpivots data so that columns become rows.&amp;#160; Today, I provide the inverse capability, although not truly generic at this point, but the technique is generic.&lt;/p&gt;  &lt;p&gt;Recently, I've been working with Microsoft System Center Configuration Management (SCCM) reporting and needed to create a pivot view of a task sequence.&amp;#160; If you're not immersed in SCCM, the example probably won't make much sense, but the technique for generating the view may be useful for other scenarios.&amp;#160; SCCM provides a lot, (and I mean ALOT) of views and reports out of the box and it provides the ability to create your own reports.&amp;#160; SCCM 2007 stores all of it's data in a SQL Server 2005 database along with the views.&amp;#160; For more about SCCM, see &lt;a title="http://www.microsoft.com/systemcenter/configurationmanager/en/us/default.aspx" href="http://www.microsoft.com/systemcenter/configurationmanager/en/us/default.aspx"&gt;http://www.microsoft.com/systemcenter/configurationmanager/en/us/default.aspx&lt;/a&gt;.&amp;#160; For more about creating custom reports, see &lt;a title="http://www.microsoft.com/downloads/details.aspx?FamilyId=87BBE64E-5439-4FC8-BECC-DEB372A40F4A&amp;amp;displaylang=en" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=87BBE64E-5439-4FC8-BECC-DEB372A40F4A&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyId=87BBE64E-5439-4FC8-BECC-DEB372A40F4A&amp;amp;displaylang=en&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;As much as I'd like to get into SCCM more, let's focus on the pivot view generation which is applicable to any scenario.&amp;#160; In our scenario, we have multiple steps for which to report the status for a task sequence.&amp;#160; A task sequence is a series of tasks to perform on a selected set of computers (known as a collection).&amp;#160; You can think of it as a workflow, and SCCM lets you define whether a sub-task must complete successfully, or may be allowed to fail and allow the task sequence to continue.&amp;#160; Task sequences may be re-run on a given machine.&amp;#160; &lt;/p&gt;  &lt;p&gt;Our business case is that we need to track how well our task sequences are doing and we want to drill down on specific sub-tasks (steps) that have meaning to our specific workflow and provide a single view of how all the sub-tasks performed within a date range.&lt;/p&gt;  &lt;p&gt;SCCM captures this information in a view they provide called I created a view on top of this to ensure that only the distinct steps are captured per advertisement)&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;VIEW&lt;/span&gt; [dbo].[V_Step_Summary] &lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; AdvertisementId, Step, 
&lt;span class="kwrd"&gt;SUM&lt;/span&gt;(&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ExitCode = 0 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; 1 &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; 0 &lt;span class="kwrd"&gt;END&lt;/span&gt;) &lt;span class="kwrd"&gt;AS&lt;/span&gt; SuccessCount,
&lt;span class="kwrd"&gt;SUM&lt;/span&gt;(&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ExitCode &amp;lt;&amp;gt; 0 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; 1 &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; 0 &lt;span class="kwrd"&gt;END&lt;/span&gt;) &lt;span class="kwrd"&gt;AS&lt;/span&gt; FailureCount,
&lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;AS&lt;/span&gt; AttemptCount
&lt;span class="kwrd"&gt;FROM&lt;/span&gt; [dbo].[v_TaskExecutionStatus]
&lt;span class="kwrd"&gt;GROUP&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; AdvertisementId, Step&lt;/pre&gt;

&lt;p&gt;I also created a view for extracting the status of the steps by date since the underlying data is stored by date/time, and this is SQL 2005, so I can't just down-convert to date.&amp;#160; I need to be able to group by date, so that the users can see the count of success/failures in a single day.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;VIEW&lt;/span&gt; [dbo].[V_Step_Summary_ByDate] &lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt; 100 &lt;span class="kwrd"&gt;PERCENT&lt;/span&gt; AdvertisementId, Step, 
DATEADD(DD,DATEDIFF(DD,0,ExecutionTime),0) &lt;span class="kwrd"&gt;AS&lt;/span&gt; ExecutionDate,
&lt;span class="kwrd"&gt;SUM&lt;/span&gt;(&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ExitCode = 0 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; 1 &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; 0 &lt;span class="kwrd"&gt;END&lt;/span&gt;) &lt;span class="kwrd"&gt;AS&lt;/span&gt; SuccessCount,
&lt;span class="kwrd"&gt;SUM&lt;/span&gt;(&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ExitCode &amp;lt;&amp;gt; 0 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; 1 &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; 0 &lt;span class="kwrd"&gt;END&lt;/span&gt;) &lt;span class="kwrd"&gt;AS&lt;/span&gt; FailureCount,
&lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;AS&lt;/span&gt; AttemptCount
&lt;span class="kwrd"&gt;FROM&lt;/span&gt; [dbo].[v_TaskExecutionStatus]
&lt;span class="kwrd"&gt;GROUP&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; AdvertisementId, Step, 
DATEADD(DD,DATEDIFF(DD,0,ExecutionTime),0) &lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;OK, so now we have the building blocks, let's look at the views that pivot the data.&amp;#160; We have 3 views: 1 to pivot just the success count, 1 to pivot just the failure count, and 1 to outer join both together to give us both failures and success.&lt;/p&gt;

&lt;p&gt;Brace yourself, here are the views:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;font size="1"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;VIEW&lt;/span&gt; [dbo].[V_StepPivot_SuccessCount] &lt;span class="kwrd"&gt;AS&lt;/span&gt;   &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 
  AdvertisementID, ExecutionDate, &lt;span class="str"&gt;'SuccessCount'&lt;/span&gt; &lt;span class="kwrd"&gt;as&lt;/span&gt; CountType,
 [00] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S00],
 [01] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S01],
 [02] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S02],
 [03] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S03],
 [04] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S04],
 [05] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S05],
 [06] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S06],
 [07] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S07],
 [08] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S08],
 [09] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S09],
 [10] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S10],
 [11] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S11],
 [12] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S12],
 [13] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S13],
 [14] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S14],
 [15] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S15],
 [16] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S16],
 [17] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S17],
 [18] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S18],
 [19] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S19],
 [20] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S20],
 [21] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S21],
 [22] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S22],
 [23] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S23],
 [24] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S24],
 [25] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S25],
 [26] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S26],
 [27] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S27],
 [28] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S28],
 [29] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S29],
 [30] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S30],
 [31] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S31],
 [32] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S32],
 [33] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S33],
 [34] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S34],
 [35] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S35],
 [36] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S36],
 [37] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S37],
 [38] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S38],
 [39] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S39],
 [40] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S40],
 [41] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S41],
 [42] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S42],
 [43] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S43],
 [44] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S44],
 [45] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S45],
 [46] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S46],
 [47] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S47],
 [48] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S48],
 [49] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S49],
 [50] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S50],
 [51] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S51],
 [52] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S52],
 [53] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S53],
 [54] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S54],
 [55] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S55],
 [56] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S56],
 [57] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S57],
 [58] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S58],
 [59] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S59],
 [60] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S60],
 [61] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S61],
 [62] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S62],
 [63] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S63],
 [64] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S64],
 [65] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S65],
 [66] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S66],
 [67] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S67],
 [68] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [S68]
  &lt;span class="kwrd"&gt;FROM&lt;/span&gt;  (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; AdvertisementID,   ExecutionDate,Step,SuccessCount &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary_ByDate) p
 PIVOT (&lt;span class="kwrd"&gt;SUM&lt;/span&gt; (SuccessCount) &lt;span class="kwrd"&gt;For&lt;/span&gt; Step &lt;span class="kwrd"&gt;in&lt;/span&gt; (
 [00],
 [01],
 [02],
 [03],
 [04],
 [05],
 [06],
 [07],
 [08],
 [09],
 [10],
 [11],
 [12],
 [13],
 [14],
 [15],
 [16],
 [17],
 [18],
 [19],
 [20],
 [21],
 [22],
 [23],
 [24],
 [25],
 [26],
 [27],
 [28],
 [29],
 [30],
 [31],
 [32],
 [33],
 [34],
 [35],
 [36],
 [37],
 [38],
 [39],
 [40],
 [41],
 [42],
 [43],
 [44],
 [45],
 [46],
 [47],
 [48],
 [49],
 [50],
 [51],
 [52],
 [53],
 [54],
 [55],
 [56],
 [57],
 [58],
 [59],
 [60],
 [61],
 [62],
 [63],
 [64],
 [65],
 [66],
 [67],
 [68]
     )) &lt;span class="kwrd"&gt;AS&lt;/span&gt; PVT
&lt;span class="kwrd"&gt;GO&lt;/span&gt;
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;VIEW&lt;/span&gt; [dbo].[V_StepPivot_FailureCount] &lt;span class="kwrd"&gt;AS&lt;/span&gt;   &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 
  AdvertisementID, ExecutionDate, &lt;span class="str"&gt;'FailureCount'&lt;/span&gt; &lt;span class="kwrd"&gt;as&lt;/span&gt; CountType,
 [00] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F00],
 [01] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F01],
 [02] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F02],
 [03] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F03],
 [04] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F04],
 [05] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F05],
 [06] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F06],
 [07] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F07],
 [08] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F08],
 [09] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F09],
 [10] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F10],
 [11] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F11],
 [12] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F12],
 [13] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F13],
 [14] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F14],
 [15] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F15],
 [16] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F16],
 [17] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F17],
 [18] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F18],
 [19] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F19],
 [20] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F20],
 [21] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F21],
 [22] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F22],
 [23] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F23],
 [24] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F24],
 [25] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F25],
 [26] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F26],
 [27] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F27],
 [28] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F28],
 [29] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F29],
 [30] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F30],
 [31] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F31],
 [32] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F32],
 [33] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F33],
 [34] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F34],
 [35] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F35],
 [36] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F36],
 [37] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F37],
 [38] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F38],
 [39] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F39],
 [40] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F40],
 [41] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F41],
 [42] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F42],
 [43] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F43],
 [44] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F44],
 [45] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F45],
 [46] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F46],
 [47] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F47],
 [48] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F48],
 [49] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F49],
 [50] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F50],
 [51] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F51],
 [52] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F52],
 [53] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F53],
 [54] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F54],
 [55] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F55],
 [56] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F56],
 [57] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F57],
 [58] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F58],
 [59] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F59],
 [60] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F60],
 [61] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F61],
 [62] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F62],
 [63] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F63],
 [64] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F64],
 [65] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F65],
 [66] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F66],
 [67] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F67],
 [68] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F68]
  &lt;span class="kwrd"&gt;FROM&lt;/span&gt;  (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; AdvertisementID,   ExecutionDate,Step,FailureCount &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary_ByDate) p
 PIVOT (&lt;span class="kwrd"&gt;SUM&lt;/span&gt; (FailureCount) &lt;span class="kwrd"&gt;For&lt;/span&gt; Step &lt;span class="kwrd"&gt;in&lt;/span&gt; (
 [00],
 [01],
 [02],
 [03],
 [04],
 [05],
 [06],
 [07],
 [08],
 [09],
 [10],
 [11],
 [12],
 [13],
 [14],
 [15],
 [16],
 [17],
 [18],
 [19],
 [20],
 [21],
 [22],
 [23],
 [24],
 [25],
 [26],
 [27],
 [28],
 [29],
 [30],
 [31],
 [32],
 [33],
 [34],
 [35],
 [36],
 [37],
 [38],
 [39],
 [40],
 [41],
 [42],
 [43],
 [44],
 [45],
 [46],
 [47],
 [48],
 [49],
 [50],
 [51],
 [52],
 [53],
 [54],
 [55],
 [56],
 [57],
 [58],
 [59],
 [60],
 [61],
 [62],
 [63],
 [64],
 [65],
 [66],
 [67],
 [68]
     )) &lt;span class="kwrd"&gt;AS&lt;/span&gt; PVT

&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;VIEW&lt;/span&gt; [dbo].[V_StepPivot_FailureCount] &lt;span class="kwrd"&gt;AS&lt;/span&gt;   &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 
  AdvertisementID, ExecutionDate, &lt;span class="str"&gt;'FailureCount'&lt;/span&gt; &lt;span class="kwrd"&gt;as&lt;/span&gt; CountType,
 [00] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F00],
 [01] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F01],
 [02] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F02],
 [03] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F03],
 [04] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F04],
 [05] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F05],
 [06] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F06],
 [07] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F07],
 [08] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F08],
 [09] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F09],
 [10] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F10],
 [11] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F11],
 [12] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F12],
 [13] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F13],
 [14] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F14],
 [15] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F15],
 [16] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F16],
 [17] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F17],
 [18] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F18],
 [19] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F19],
 [20] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F20],
 [21] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F21],
 [22] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F22],
 [23] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F23],
 [24] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F24],
 [25] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F25],
 [26] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F26],
 [27] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F27],
 [28] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F28],
 [29] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F29],
 [30] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F30],
 [31] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F31],
 [32] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F32],
 [33] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F33],
 [34] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F34],
 [35] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F35],
 [36] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F36],
 [37] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F37],
 [38] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F38],
 [39] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F39],
 [40] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F40],
 [41] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F41],
 [42] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F42],
 [43] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F43],
 [44] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F44],
 [45] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F45],
 [46] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F46],
 [47] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F47],
 [48] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F48],
 [49] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F49],
 [50] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F50],
 [51] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F51],
 [52] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F52],
 [53] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F53],
 [54] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F54],
 [55] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F55],
 [56] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F56],
 [57] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F57],
 [58] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F58],
 [59] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F59],
 [60] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F60],
 [61] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F61],
 [62] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F62],
 [63] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F63],
 [64] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F64],
 [65] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F65],
 [66] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F66],
 [67] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F67],
 [68] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [F68]
  &lt;span class="kwrd"&gt;FROM&lt;/span&gt;  (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; AdvertisementID,   ExecutionDate,Step,FailureCount &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary_ByDate) p
 PIVOT (&lt;span class="kwrd"&gt;SUM&lt;/span&gt; (FailureCount) &lt;span class="kwrd"&gt;For&lt;/span&gt; Step &lt;span class="kwrd"&gt;in&lt;/span&gt; (
 [00],
 [01],
 [02],
 [03],
 [04],
 [05],
 [06],
 [07],
 [08],
 [09],
 [10],
 [11],
 [12],
 [13],
 [14],
 [15],
 [16],
 [17],
 [18],
 [19],
 [20],
 [21],
 [22],
 [23],
 [24],
 [25],
 [26],
 [27],
 [28],
 [29],
 [30],
 [31],
 [32],
 [33],
 [34],
 [35],
 [36],
 [37],
 [38],
 [39],
 [40],
 [41],
 [42],
 [43],
 [44],
 [45],
 [46],
 [47],
 [48],
 [49],
 [50],
 [51],
 [52],
 [53],
 [54],
 [55],
 [56],
 [57],
 [58],
 [59],
 [60],
 [61],
 [62],
 [63],
 [64],
 [65],
 [66],
 [67],
 [68]
     )) &lt;span class="kwrd"&gt;AS&lt;/span&gt; PVT
&lt;span class="kwrd"&gt;GO&lt;/span&gt;
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;VIEW&lt;/span&gt; [dbo].[V_StepPivot_Count] &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; sc.AdvertisementID,   sc.ExecutionDate,  
 [S00], [F00],
 [S01], [F01],
 [S02], [F02],
 [S03], [F03],
 [S04], [F04],
 [S05], [F05],
 [S06], [F06],
 [S07], [F07],
 [S08], [F08],
 [S09], [F09],
 [S10], [F10],
 [S11], [F11],
 [S12], [F12],
 [S13], [F13],
 [S14], [F14],
 [S15], [F15],
 [S16], [F16],
 [S17], [F17],
 [S18], [F18],
 [S19], [F19],
 [S20], [F20],
 [S21], [F21],
 [S22], [F22],
 [S23], [F23],
 [S24], [F24],
 [S25], [F25],
 [S26], [F26],
 [S27], [F27],
 [S28], [F28],
 [S29], [F29],
 [S30], [F30],
 [S31], [F31],
 [S32], [F32],
 [S33], [F33],
 [S34], [F34],
 [S35], [F35],
 [S36], [F36],
 [S37], [F37],
 [S38], [F38],
 [S39], [F39],
 [S40], [F40],
 [S41], [F41],
 [S42], [F42],
 [S43], [F43],
 [S44], [F44],
 [S45], [F45],
 [S46], [F46],
 [S47], [F47],
 [S48], [F48],
 [S49], [F49],
 [S50], [F50],
 [S51], [F51],
 [S52], [F52],
 [S53], [F53],
 [S54], [F54],
 [S55], [F55],
 [S56], [F56],
 [S57], [F57],
 [S58], [F58],
 [S59], [F59],
 [S60], [F60],
 [S61], [F61],
 [S62], [F62],
 [S63], [F63],
 [S64], [F64],
 [S65], [F65],
 [S66], [F66],
 [S67], [F67],
 [S68], [F68]
  &lt;span class="kwrd"&gt;FROM&lt;/span&gt; V_StepPivot_FailureCount fc
   &lt;span class="kwrd"&gt;FULL&lt;/span&gt; &lt;span class="kwrd"&gt;OUTER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; V_StepPivot_SuccessCount sc 
    &lt;span class="kwrd"&gt;ON&lt;/span&gt; sc.AdvertisementId = fc.AdvertisementId
     &lt;span class="kwrd"&gt;AND&lt;/span&gt; sc.ExecutionDate = fc.ExecutionDate&lt;/font&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Wow, 68 columns are required - 1 for each step!&amp;#160; That's a lot of pivoting.&amp;#160; If you think I typed in all 68 column names, you're wrong!&amp;#160; I generated the code using the below stored procedure.&amp;#160; I didn't bother using SP_EXECUTESQL - just output and then manually cut and paste the output into a new query window and then run it from there.&amp;#160; It wouldn't be that hard to put this all into a variable and then execute the variable to build the view directly from the stored proc.&amp;#160; Note the retrieval from V_Step_Summary in order to generate the list of columns&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;font size="1"&gt;&lt;font face="Arial Narrow"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [dbo].[USP_Generate_StepPivot_Views_V3] &lt;span class="kwrd"&gt;AS&lt;/span&gt; 
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'CREATE VIEW V_StepPivot_SuccessCount AS   SELECT '&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; Line
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'  AdvertisementID, ExecutionDate, '&lt;/span&gt;&lt;span class="str"&gt;'SuccessCount'&lt;/span&gt;&lt;span class="str"&gt;' as CountType,'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="kwrd"&gt;distinct&lt;/span&gt; 
      (&lt;span class="str"&gt;' ['&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) + &lt;span class="str"&gt;']'&lt;/span&gt;) 
    +
      (&lt;span class="str"&gt;' AS [S'&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) + 
    (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP = (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;MAX&lt;/span&gt;(STEP) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; V_Step_Summary) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;']'&lt;/span&gt; &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="str"&gt;'],'&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;))
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary

    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'  FROM  (SELECT AdvertisementID,   ExecutionDate,Step,SuccessCount FROM dbo.V_Step_Summary_ByDate) p'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;' PIVOT (SUM (SuccessCount) For Step in ('&lt;/span&gt;
&lt;/font&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;strong&gt;&lt;font color="#ff0000" face="Arial Narrow"&gt;    &lt;br /&gt;&lt;/font&gt;&lt;font face="Arial Narrow"&gt;&lt;font color="#ff0000"&gt;&lt;font size="3"&gt;--  This part generates the pivoted column list by selecting the distinct rows that &lt;br /&gt;-- correspond to the pivot columns to create.  The case statement is used to identify&lt;br /&gt;-- the last step.&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;strong&gt;&lt;font face="Arial Narrow"&gt;&lt;font color="#ff0000"&gt;&lt;font size="3"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;strong&gt;&lt;font face="Arial Narrow"&gt;&lt;font color="#ff0000"&gt;&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;font face="Arial Narrow"&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;&lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="kwrd"&gt;distinct&lt;/span&gt; 
      (&lt;span class="str"&gt;' ['&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) +
    (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP = (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;MAX&lt;/span&gt;(STEP) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; V_Step_Summary) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;']'&lt;/span&gt; &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="str"&gt;'],'&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;))
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;font size="1"&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;&lt;/font&gt;&lt;/strong&gt;
&lt;font face="Arial Narrow"&gt;    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'     )) AS PVT'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'GO'&lt;/span&gt;

    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'CREATE VIEW V_StepPivot_FailureCount AS   SELECT '&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; Line
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'  AdvertisementID, ExecutionDate, '&lt;/span&gt;&lt;span class="str"&gt;'FailureCount'&lt;/span&gt;&lt;span class="str"&gt;' as CountType,'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="kwrd"&gt;distinct&lt;/span&gt; 
      (&lt;span class="str"&gt;' ['&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) +&lt;span class="str"&gt;']'&lt;/span&gt;)
    +
      (&lt;span class="str"&gt;' AS [F'&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) + 
    (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP = (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;MAX&lt;/span&gt;(STEP) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; V_Step_Summary) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;']'&lt;/span&gt; &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="str"&gt;'],'&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;))
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'  FROM  (SELECT AdvertisementID,   ExecutionDate,Step,FailureCount FROM dbo.V_Step_Summary_ByDate) p'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;/font&gt;&lt;span class="str"&gt;&lt;font face="Arial Narrow"&gt;' PIVOT (SUM (FailureCount) For Step in ('&lt;br /&gt;&lt;/font&gt;&lt;/span&gt;&lt;font face="Arial Narrow"&gt;&lt;font color="#ff0000" size="3"&gt;&lt;strong&gt;-- This part generates the pivoted column list by selecting the distinct rows that &lt;br /&gt;-- correspond to the pivot columns to create.  &lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;strong&gt;&lt;font face="Arial Narrow"&gt;&lt;font color="#ff0000"&gt;&lt;font size="3"&gt;The case statement is used to identify&lt;br /&gt;-- the last step.&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;font face="Arial Narrow"&gt;
&lt;strong&gt;&lt;font color="#ff0000"&gt;    &lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;font face="Arial Narrow"&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;&lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="kwrd"&gt;distinct&lt;/span&gt; 
      (&lt;span class="str"&gt;' ['&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) +
    (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP = (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;MAX&lt;/span&gt;(STEP) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; V_Step_Summary) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;']'&lt;/span&gt; &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="str"&gt;'],'&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;))
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary&lt;/font&gt;&lt;/strong&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'     )) AS PVT'&lt;/span&gt;

    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'GO'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'CREATE VIEW V_StepPivot_Count AS SELECT sc.AdvertisementID,   sc.ExecutionDate, '&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="kwrd"&gt;distinct&lt;/span&gt; 
      (&lt;span class="str"&gt;' [S'&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) + &lt;span class="str"&gt;'],'&lt;/span&gt; 
    +
      (&lt;span class="str"&gt;' [F'&lt;/span&gt; + (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP &amp;lt; 10 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'0'&lt;/span&gt; + &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(1), STEP) &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),Step) &lt;span class="kwrd"&gt;END&lt;/span&gt;) 
    +
    (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; STEP = (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;MAX&lt;/span&gt;(STEP) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; V_Step_Summary) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;']'&lt;/span&gt; &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="str"&gt;'],'&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;)))
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; dbo.V_Step_Summary
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'  FROM V_StepPivot_FailureCount fc'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'   FULL OUTER JOIN V_StepPivot_SuccessCount sc '&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'    ON sc.AdvertisementId = fc.AdvertisementId'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'     AND sc.ExecutionDate = fc.ExecutionDate'&lt;/span&gt;
    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'GO'&lt;/span&gt;
END&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;OK, so you ask &amp;quot;how long did it take you to write that stored procedure&amp;quot;?&amp;#160; Didn't it take longer than if you'd just written the views by hand?&amp;#160; Yes, probably did, but not by much.&amp;#160; And I didn't have to spend much time testing the output view, since it was generated directly from the data that defines the view as being correct.&amp;#160; Plus what happens if the number of steps change, do I want to change the pivot view by hand each time?&amp;#160; For example, we could actually&amp;#160; modify the stored proc to put the code into a variable which it then executes, rather than outputting.&amp;#160; Once that is in place, we can create a scheduled task to automatically run this stored procedure on a scheduled basis to ensure that the pivot view is always correct.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ac70ea43-6f67-44a5-8750-f9ed8bfdafa9" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SQL+Server" rel="tag"&gt;SQL Server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SCCM" rel="tag"&gt;SCCM&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Tips" rel="tag"&gt;Tips&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9828953" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server+2005/default.aspx">SQL Server 2005</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/T-SQL+Tips+and+Tricks/default.aspx">T-SQL Tips and Tricks</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/SCCM/default.aspx">SCCM</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Code+Generation/default.aspx">Code Generation</category></item><item><title>Software writing software</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/07/08/software-writing-software.aspx</link><pubDate>Wed, 08 Jul 2009 22:42:31 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9824656</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9824656.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9824656</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9824656</wfw:comment><description>&lt;p&gt;My academic research relates to software automation – for me that means code writing code.&amp;#160; Most code generators today are pretty stupid, though.&amp;#160; My hypothesis is basically that software should be able to learn from experience so that it can not only generate tedious code, but also discover algorithms based on results of code execution.&amp;#160; So, my goal isn’t just to develop software that generates mundane code components like simple data classes or default stored procedures, but build generators that learn from examining the environment along with trial and error in order to write intelligent systems.&lt;/p&gt;  &lt;p&gt;To illustrate this point, I am using Towers of Hanoi as a proof-of-concept of a very simple example for how software can learn an algorithm and then write code that includes the algorithm for a problem domain.&amp;#160; The recursive algorithm for solving towers of Hanoi is rather simple – see&amp;#160; &lt;a title="http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html" href="http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html"&gt;http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html&lt;/a&gt;.&amp;#160; I found an example in C# for solving the puzzle using the recursive algorithm at &lt;a title="http://azerdark.blogspot.com/2008/07/c-tower-of-hanoi.html" href="http://azerdark.blogspot.com/2008/07/c-tower-of-hanoi.html"&gt;http://azerdark.blogspot.com/2008/07/c-tower-of-hanoi.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Here is a walk-through: &lt;/p&gt;  &lt;p&gt;Let Hn = # moves for a stack of n disks. &lt;/p&gt;  &lt;p&gt;Here is the optimal strategy: &lt;/p&gt;  &lt;p&gt;Move top n−1 disks to spare peg. (Hn−1 moves) &lt;/p&gt;  &lt;p&gt;Move bottom disk. (1 move) &lt;/p&gt;  &lt;p&gt;Move top n−1 to bottom disk. (Hn−1 moves) &lt;/p&gt;  &lt;p&gt;Note that: Hn = 2Hn−1 + 1 &lt;/p&gt;  &lt;p&gt;The # of moves is described by the below recurrence relation: &lt;/p&gt;  &lt;p&gt;Solving Tower of Hanoi RR&amp;#160; &lt;/p&gt;  &lt;p&gt;Hn = 2 Hn−1 + 1 &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; = 2 (2 Hn−2 + 1) + 1&amp;#160; = 22 Hn−2 + 2 + 1 &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; = 22(2 Hn−3 + 1) + 2 + 1 = 23 Hn−3 + 22 + 2 + 1 &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; … &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; = 2n−1 H1 + 2n−2 + … + 2 + 1 &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; = 2n−1 + 2n−2 + … + 2 + 1&amp;#160; (since H1 = 1) &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; =&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; = 2n − 1 &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;The code is fairly trivial:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;procedure Hanoi(n: integer; source, dest, by: &lt;span class="kwrd"&gt;char&lt;/span&gt;);
Begin
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (n=1) then
        writeln(&lt;span class="str"&gt;'Move the plate from '&lt;/span&gt;, source, &lt;span class="str"&gt;' to '&lt;/span&gt;, dest)
    &lt;span class="kwrd"&gt;else&lt;/span&gt; begin
        Hanoi(n-1, source, by, dest);
        Hanoi(1, source, dest, by);
        Hanoi(n-1, by, dest, source);
    end;
End;&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;But, suppose I didn’t know the algorithm and I want to write code that can discover the algorithm for the game (or potentially any other game) by simply playing the game and looking for patterns.&amp;#160; To do such a task requires a framework for capturing the moves and analyzing the states of all the pieces (variables) involved.&amp;#160; The framework also needs to be able to know the rules are for performing the moves and how to determine if victory is achieved.&amp;#160; In order to do this, I could have targeted the Hanoi puzzle specifically, but I want a framework that will work for potentially any game.&amp;#160; &lt;/p&gt;

&lt;p&gt;Enter the Gaming Automation Framework (GAF).&amp;#160; To build this framework, I utilize SQL Server 2008 as my storage engine as well as leveraging functions and triggers in order to support a schema that not only supports playing the game, but also enforces rules on a game-by-game basis and supports functions for checking the status of a game as well as dictating the best moves.&lt;/p&gt;

&lt;p&gt;Here is an overview of the GAF Components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Game Instantiation SQL Server Database 
    &lt;ul&gt;
      &lt;li&gt;Schema for game definitions and instantiation of games &lt;/li&gt;

      &lt;li&gt;Database trigger framework for invoking functions enforcing rules that are specific to the game being played and for recording state of the game after each move. &lt;/li&gt;

      &lt;li&gt;Stored procedures for creating games, game instances, performing moves, and undoing moves. &lt;/li&gt;

      &lt;li&gt;Database function framework for defining what constitutes a valid move and what state arrangement defines success (i.e. winning the game). &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;Game Player/Solver windows form 
    &lt;ul&gt;
      &lt;li&gt;Specification of the game to play along with the number of variable instantiations (i.e. for tower of Hanoi we might chose 3 disks, 4 disks, 5 disks, etc.&amp;#160; For checkers we might chose 8 or 12 pieces, etc.) &lt;/li&gt;

      &lt;li&gt;Function to play game using depth-first-search (DFS) to probe all moves in order to generate a solution. &lt;/li&gt;

      &lt;li&gt;Function to analyze the game moves and determine a pattern and generate code to automatically solve the game (I’m still working on this part). &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s step through the major components:&amp;#160; &lt;/p&gt;

&lt;p&gt;Below are the schemas for game and game variable.&amp;#160; Currently this only supports contiguous value check for the variables.&amp;#160; I plan to improve this by allowing a discrete ranges to be associated with the variables.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Games].[Game](
    [GameId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [GameName] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](50) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [MoveRuleFunctionName] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](256) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;–- function to get list of valid moves&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;    [GameStatusFunctionName] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](256) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;–- function to check if game over/won/lost&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;    [BestMoveRuleFunctionName] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](256) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
 &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_Game_1] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
(
    [GameId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;
))&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Games].[GameVariable](&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;-- The “domain” of pieces”
    [GameId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [VariableId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [VariableName] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](50) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [MinInstances] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, -- Mininum number of “pieces”
    [MaxInstances] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, – Max number of pieces.
    [SimulationInstances] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;-– This is the number of brute force simulations&lt;br /&gt;-- to perform in order to find a solution, not currently using.&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;    [MinValue] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;–- min value or (range) (i.e. 1 for peg 1 for Hanoi &lt;br /&gt;-- that the piece interacts with&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;    [MaxValue] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;–- max value (i.e. 3 for Hanoi for peg 3&lt;/pre&gt;

&lt;p&gt;&amp;#160;&amp;#160;&amp;#160; [StartValue] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 

  &lt;br /&gt;-- staring value of the piece – i.e. peg 1 for Hanoi 

  &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&amp;#160; &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_GameVariable] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 

  &lt;br /&gt;( 

  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; [VariableId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt; 

  &lt;br /&gt;)&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;So for the Tower of Hanoi, we define 3 variable rows to represent the disks and use the min and max value to control what peg the disks may be placed on.&lt;/p&gt;

&lt;p&gt;Game Table Data:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image_2.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image_thumb.png" width="244" height="67" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The game table provides a level of abstraction from the specific game by storing metadata about how to play the game, check the status, and win the game in terms of the names of the functions.&amp;#160; This allows multiple games to be setup with different rules.&amp;#160; The simulation engine can then evaluate for a particular instance of a game&amp;#160; which functions apply.&lt;/p&gt;

&lt;p&gt;Games.GameVariable 
  &lt;br /&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image4_thumb.png" width="244" height="197" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The game variable relates to the game table and provides information on the variables to be used.&amp;#160; I use the terms “variable”/“domain”/”game piece” and “domain”, ”value”, “location” interchangeably not just to confuse you, but because these are different ways to think of these entities depending on the type of scenario we are solving for.&amp;#160; However, they are analogous and represent the mapping of a variable-value assignment.&amp;#160;&amp;#160; This could be a game piece/location, but could represent other types of domain/range pairs.&amp;#160; &lt;/p&gt;

&lt;p&gt;For our tower of Hanoi example, we only use a single variable to represent the disk and use the instance fields to control how many disks there are.&amp;#160; In a a game where there are different types of pieces, separate variables would be created.&amp;#160; To represent the valid states of the variable – we utilize start value to represent starting position, final value to represent winning position, and min and max to control the range of values.&amp;#160; I plan to improve this so that not only can a range of values, but so that discrete sets of values can be used.&amp;#160; For Tower of Hanoi, however this suffices.&lt;/p&gt;

&lt;p&gt;Here are the tables used to support instances of the game.&amp;#160; Note the use of the columns to store game-state for each move.&amp;#160; This is the key component used for the automation aspect in order to discover patterns and translate into a solution algorithm.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Games].[Instance](
    [InstanceId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [GameId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [GameDescription] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](255) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [VariableInstanceCount] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [DomainStates] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](&lt;span class="kwrd"&gt;max&lt;/span&gt;) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;-– Each char represents a move and the value in the character &lt;br /&gt;-- is the variable moved. (i.e. disk number)
    [RangeStates] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](&lt;span class="kwrd"&gt;max&lt;/span&gt;) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;-– Each char represents a move and the value in the character &lt;br /&gt;-- is the value mapped to the moved variable (i.e. peg)
    [GameStatus]  &lt;span class="kwrd"&gt;AS&lt;/span&gt; ([games].[fn_CheckHanoiGameStatus]([InstanceId],(1))),
 &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_GameInstance] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
(
    [InstanceId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;
))&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Games].[InstanceMove](
    [InstanceMoveId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [MoveNumber] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [InstanceId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [InstanceVariableId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;-- The “piece” that was moved
    [InstanceVariableValue] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;-– The “location” that piece moved to
 &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_GameMove] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
(
    [InstanceMoveId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;
))&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Games].[InstanceVariable](&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;-- Current value for the piece (“domain&amp;quot; or variable) &lt;br /&gt;-- and location (“range” or value)
    [InstanceVariableId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [VariableId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [InstanceId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [VariableCurrentValue] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
    [InstanceVariableNumber] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
 &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_MovePosition] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
(
    [InstanceVariableId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;
))&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Games].[InstanceVariableValueStates](
-- One per combination of domain and range (piece/location)&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;    [InstanceId] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [InstanceVariableNumber] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [InstanceVariableValue] [&lt;span class="kwrd"&gt;int&lt;/span&gt;] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [MoveStates] [&lt;span class="kwrd"&gt;varchar&lt;/span&gt;](&lt;span class="kwrd"&gt;max&lt;/span&gt;) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, &lt;br /&gt;–- Bit mask indicating if the variable &lt;br /&gt;-- was moved on the bit corresponding to the move to the specified value.&lt;/pre&gt;

&lt;pre class="csharpcode"&gt; &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_InstanceVariableValueStates] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; 
(
    [InstanceId] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;,
    [InstanceVariableNumber] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;,
    [InstanceVariableValue] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;font color="#0000ff"&gt;-- Please don’t get mad I’m using a compound primary key instead of generating &lt;/font&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;font color="#0000ff"&gt;–- &lt;/font&gt;&lt;font color="#0000ff"&gt;a surrogate, think of this as mainly a logical design at this point…&lt;/font&gt;
)&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;p&gt;Here is the relationship diagram that shows how games and game instances inter-relate.&amp;#160; The game instance is just that – an instance of a game, we could have multiple instances per games.&amp;#160; Note that this isn’t a perfectly normalized design, some redundancy has been put in to avoid having to write complex queries to link game moves and their variables states back to the instance.&amp;#160; We can clean that up later.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image41%5B1%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image41%5B1%5D_thumb.png" width="440" height="484" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;A trigger automatically sets the move number and sets the values in the Instance InstanceVariable after each move as well as performing some other tasks that we will get into later.&amp;#160; Having the latest instance variable value is handy for processes that involve checking rules, etc, because they are interested in the latest state.&amp;#160;&amp;#160; They are usually interested in the prior state, also, so I’ll probably enhance this to store the prior value as well.&lt;/p&gt;

&lt;pre class="csharpcode"&gt; &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TRIGGER&lt;/span&gt; [Games].[InstanceMove_ITrig]
   &lt;span class="kwrd"&gt;ON&lt;/span&gt;  [Games].[InstanceMove]
   &lt;span class="kwrd"&gt;AFTER&lt;/span&gt; INSERT
&lt;span class="kwrd"&gt;AS&lt;/span&gt; 
BEGIN&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @InstanceId &lt;span class="kwrd"&gt;INT&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @InstanceVariableNumber &lt;span class="kwrd"&gt;INT&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @InstanceVariableValue &lt;span class="kwrd"&gt;INT&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @LastVariableNumber &lt;span class="kwrd"&gt;INT&lt;/span&gt; = –1 &lt;br /&gt;&lt;span class="rem"&gt;-- To force variable to be evaluated as null&lt;br /&gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @OldVariableValue &lt;span class="kwrd"&gt;INT&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @InstanceMoveId &lt;span class="kwrd"&gt;INT&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @CustomErrorMessage &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(255)=&lt;span class="str"&gt;''&lt;/span&gt;
    
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; XACT_ABORT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; &lt;span class="kwrd"&gt;TRANSACTION&lt;/span&gt;
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; TRY 
        &lt;span class="rem"&gt;-- Get variable information&lt;/span&gt;
        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 
            @InstanceId = INSERTED.InstanceId , 
            @InstanceMoveId = INSERTED.InstanceMoveId,
            @InstanceVariableValue= INSERTED.InstanceVariableValue,
            @InstanceVariableNumber = iv.InstanceVariableNumber 
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; INSERTED 
            &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt;  Games.InstanceVariable iv
            &lt;span class="kwrd"&gt;ON&lt;/span&gt; iv.InstanceVariableId = INSERTED.InstanceVariableId
            
        &lt;span class="kwrd"&gt;IF&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove &lt;br /&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceID) &amp;gt; 1
        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
            &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt; 1 @LastVariableNumber = InstanceVariableNumber 
            &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove im
            &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Games.InstanceVariable iv
            &lt;span class="kwrd"&gt;ON&lt;/span&gt; im.InstanceVariableId
                = iv.InstanceVariableId
            &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; im.InstanceId = @InstanceId
            &lt;span class="kwrd"&gt;AND&lt;/span&gt; im.InstanceMoveId &amp;lt;&amp;gt; @InstanceMoveId        
            &lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; MoveNumber &lt;span class="kwrd"&gt;DESC&lt;/span&gt;
        &lt;span class="kwrd"&gt;END&lt;/span&gt;

                
        &lt;span class="rem"&gt;-- Set move number&lt;/span&gt;
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; [Games].[InstanceMove]
            &lt;span class="kwrd"&gt;SET&lt;/span&gt; MoveNumber = 
                (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; [Games].[InstanceMove] &lt;br /&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = INSERTED.InstanceId)
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; INSERTED
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; INSERTED.InstanceMoveId = InstanceMove.InstanceMoveID
        &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="rem"&gt;-- TODO: This part of the code is currently specific to Tower of Hanoi, &lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;need to use the MoveResultStatus in order&lt;/span&gt;
        &lt;span class="rem"&gt;-- to check if this is a bad move and use the mappings to display &lt;br /&gt;-- the error message.  That will &lt;/span&gt;
        &lt;span class="rem"&gt;-- allow this trigger to work for any game, not just Tower of Hanoi.&lt;/span&gt;
        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @MoveResult &lt;span class="kwrd"&gt;INT&lt;/span&gt; &lt;span class="rem"&gt;-- 1 if valid, 0 if invalid, -1 if &lt;br /&gt;-- &lt;/span&gt;&lt;span class="rem"&gt;no more moves left&lt;/span&gt;
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; @MoveResult = Games.fn_CheckHanoiMove
            (@InstanceId, @InstanceVariableNumber,@InstanceVariableValue, &lt;br /&gt;@LastVariableNumber, &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;@OldVariableValue, 1)
        &lt;span class="kwrd"&gt;IF&lt;/span&gt; @MoveResult &amp;lt;= –2 &lt;br /&gt;&lt;span class="rem"&gt;-- Ignore -1 error, since that means we just now ran out of moves, &lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;&lt;/span&gt;&lt;span class="rem"&gt;just need to error out if we have used up all moves&lt;/span&gt;
        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
            &lt;span class="kwrd"&gt;SET&lt;/span&gt; @CustomErrorMessage = &lt;span class="str"&gt;'Invalid Move: '&lt;/span&gt; + 
            (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; 
                &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveResult = -6 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'Out of Moves'&lt;/span&gt;
                &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveResult = -2 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'Destination peg '&lt;/span&gt; &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableValue) &lt;br /&gt;+ &lt;span class="str"&gt;' has a smaller disk on it already than disk '&lt;/span&gt; &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableNumber)
                &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveResult = -3 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'Source peg '&lt;/span&gt; &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@OldVariableValue) &lt;br /&gt;+ &lt;span class="str"&gt;' has a smaller disk on top than disk '&lt;/span&gt; &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableNumber)
                &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveResult = -4 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'Disk '&lt;/span&gt; &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableNumber) &lt;br /&gt;+ &lt;span class="str"&gt;' moved to same peg '&lt;/span&gt; &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableValue) + &lt;span class="str"&gt;' as it is already on'&lt;/span&gt;
                &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveResult = -5 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="str"&gt;'Disk '&lt;/span&gt; &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableNumber) &lt;br /&gt;+ &lt;span class="str"&gt;' moved twice in a row'&lt;/span&gt;
                &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveResult = -7 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;br /&gt;&lt;span class="str"&gt;'Biggest disk Must be moved to center peg at the game point in order to win '&lt;/span&gt; 
            &lt;span class="kwrd"&gt;END&lt;/span&gt;)
            &lt;span class="kwrd"&gt;RAISERROR&lt;/span&gt; (@CustomErrorMessage,16,1)
        END&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="rem"&gt;-- Update Instance Variable&lt;/span&gt;
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.InstanceVariable
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; VariableCurrentValue = Inserted.InstanceVariableValue
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; INSERTED 
        &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Games.InstanceVariable IV
        &lt;span class="kwrd"&gt;ON&lt;/span&gt; IV.InstanceVariableId = INSERTED.InstanceVariableId
        
        &lt;span class="rem"&gt;-- Update bit masks for moves&lt;/span&gt;
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.InstanceVariableValueStates
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; MoveStates = &lt;span class="kwrd"&gt;COALESCE&lt;/span&gt;(MoveStates,&lt;span class="str"&gt;''&lt;/span&gt;) + &lt;span class="str"&gt;'1'&lt;/span&gt;
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceVariableNumber = @InstanceVariableNumber
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceVariableValue= @InstanceVariableValue
         
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.InstanceVariableValueStates
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; MoveStates = &lt;span class="kwrd"&gt;COALESCE&lt;/span&gt;(MoveStates,&lt;span class="str"&gt;''&lt;/span&gt;) + &lt;span class="str"&gt;'0'&lt;/span&gt;
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; (InstanceVariableNumber = @InstanceVariableNumber
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceVariableValue= @InstanceVariableValue)
        
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.Instance
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; 
            DomainStates = &lt;span class="kwrd"&gt;COALESCE&lt;/span&gt;(DomainStates + &lt;span class="str"&gt;','&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;) &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableNumber),
            RangeStates = &lt;span class="kwrd"&gt;COALESCE&lt;/span&gt;(RangeStates + &lt;span class="str"&gt;','&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;) &lt;br /&gt;+ &lt;span class="kwrd"&gt;CONVERT&lt;/span&gt;(&lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(2),@InstanceVariableValue)
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
        &lt;span class="kwrd"&gt;COMMIT&lt;/span&gt; TRANSACTION&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;There are 4 stored procedures used to play the game&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;InsertInstance – Creates a new game.&amp;#160; Based on the passed-in number of instances which gets set on the Game, Instance variables are generated by the trigger. &lt;/li&gt;

  &lt;li&gt;InsertMove – Inserts a new move which then results in the execution of the InstanceMove_ITrig trigger above.&amp;#160; Returns back the status of the game. &lt;/li&gt;

  &lt;li&gt;UndoMove – Rolls back a move.&amp;#160; This is used when the simulator plays a “loosing” move and allows the simulator to try all different game combinations without having to start all over when hitting a dead-end.&amp;#160; &lt;/li&gt;

  &lt;li&gt;GetInstanceStates – Gets the state data from the Instance table for a particular game instance.&amp;#160; The states can then be analyzed for patterns to automate solution discovery. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are all simple stored procedures with the exception of the UndoMove:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [Games].[UndoLastMove]
    &lt;span class="rem"&gt;-- Add the parameters for the stored procedure here&lt;/span&gt;
    @InstanceId &lt;span class="kwrd"&gt;INT&lt;/span&gt;
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt; 
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; XACT_ABORT &lt;span class="kwrd"&gt;ON&lt;/span&gt;

    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @MoveNumber &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @MoveNumber = &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove &lt;br /&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId= @InstanceId
    
    &lt;span class="kwrd"&gt;IF&lt;/span&gt; @MoveNumber = 0
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; &lt;span class="rem"&gt;-- Nothing to do&lt;/span&gt;
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; &lt;span class="kwrd"&gt;TRANSACTION&lt;/span&gt;
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; TRY 
        
        &lt;span class="rem"&gt;-- Identify the variable and value affected by the last move &lt;br /&gt;-- and the last move id&lt;/span&gt;
        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @InstanceVariableId &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @InstanceVariableValue &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @InstanceMoveId &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @PriorInstanceVariableValue &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
        
        &lt;span class="rem"&gt;-- Find the current variable and value affected&lt;/span&gt;
        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @InstanceVariableId = InstanceVariableId, &lt;br /&gt;@InstanceVariableValue = InstanceVariableValue, &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;@InstanceMoveId = InstanceMoveId
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; MoveNumber = @MoveNumber

        &lt;span class="rem"&gt;-- Delete the move&lt;/span&gt;
        &lt;span class="kwrd"&gt;DELETE&lt;/span&gt; &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceMoveId = @InstanceMoveId

        &lt;span class="rem"&gt;-- Find the prior value for the variable, since the most current &lt;br /&gt;-- is now deleted&lt;/span&gt;
        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt; 1 @PriorInstanceVariableValue = 
            (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; InstanceVariableValue &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;THEN&lt;/span&gt; gv.StartValue &lt;br /&gt;&lt;span class="kwrd"&gt;ELSE&lt;/span&gt; InstanceVariableValue &lt;span class="kwrd"&gt;END&lt;/span&gt;)
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.GameVariable gv
        &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Games.InstanceVariable iv
        &lt;span class="kwrd"&gt;ON&lt;/span&gt; iv.VariableId = gv.VariableId    
        &lt;span class="kwrd"&gt;LEFT&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Games.InstanceMove im
        &lt;span class="kwrd"&gt;ON&lt;/span&gt; im.InstanceVariableId = iv.InstanceVariableId
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; iv.InstanceId = @InstanceId
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; iv.InstanceVariableId = @InstanceVariableId
        &lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; MoveNumber &lt;span class="kwrd"&gt;DESC&lt;/span&gt;
        
        &lt;span class="rem"&gt;-- Drop the last state from Games.Instance&lt;/span&gt;
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt;     Games.Instance
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; DomainStates = 
                (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveNumber &amp;gt; 1 
                    &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;SUBSTRING&lt;/span&gt;(DomainStates,1,DATALENGTH(DomainStates) - &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;CHARINDEX(&lt;span class="str"&gt;','&lt;/span&gt;,REVERSE(DomainStates))) 
                    &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;),
                RangeStates = 
                (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveNumber &amp;gt; 1 
                    &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;SUBSTRING&lt;/span&gt;(RangeStates,1,DATALENGTH(RangeStates)  - &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;CHARINDEX(&lt;span class="str"&gt;','&lt;/span&gt;,REVERSE(RangeStates)))
                    &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;)
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
        
        &lt;span class="rem"&gt;-- Drop the last bit all the Games.InstanceVariableValueStates&lt;/span&gt;
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.InstanceVariableValueStates
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; MoveStates = 
            (&lt;span class="kwrd"&gt;CASE&lt;/span&gt; &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; @MoveNumber &amp;gt; 1 &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;SUBSTRING&lt;/span&gt;(MoveStates,1,&lt;br /&gt;@MoveNumber -1)  &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="str"&gt;''&lt;/span&gt; &lt;span class="kwrd"&gt;END&lt;/span&gt;)
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
        
        &lt;span class="rem"&gt;-- Correct the current value on InstanceVariable&lt;/span&gt;
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.InstanceVariable
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; VariableCurrentValue = @PriorInstanceVariableValue
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceVariableId = @InstanceVariableId
         
        &lt;span class="kwrd"&gt;COMMIT&lt;/span&gt; &lt;span class="kwrd"&gt;TRANSACTION&lt;/span&gt;
    &lt;span class="kwrd"&gt;END&lt;/span&gt; TRY
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; CATCH
        &lt;span class="kwrd"&gt;ROLLBACK&lt;/span&gt; &lt;span class="kwrd"&gt;TRANSACTION&lt;/span&gt;
        &lt;span class="kwrd"&gt;EXECUTE&lt;/span&gt; usp_GetErrorInfo 
    &lt;span class="kwrd"&gt;END&lt;/span&gt; CATCH
&lt;span class="kwrd"&gt;END&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;FUNCTION&lt;/span&gt; [Games].[fn_CheckHanoiGameStatus]
(
    &lt;span class="rem"&gt;-- Add the parameters for the function here&lt;/span&gt;
    @InstanceId &lt;span class="kwrd"&gt;INT&lt;/span&gt;,
    @PostMoveCheck &lt;span class="kwrd"&gt;bit&lt;/span&gt; = 0
)
&lt;span class="kwrd"&gt;RETURNS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt;
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="rem"&gt;-- Declare the return variable here&lt;/span&gt;
    &lt;span class="rem"&gt;-- -1 = Game lost, 0 = Undecided, 1 = Game won, -2 = Game not started&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @ResultVar &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @NumberOfDisks &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0 
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @NumberOfMoves &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @NumberOfDisksOnLastPeg &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @MaxMoves &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @LastMoveVariableId &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @TwoMovesBackVariableId &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @MinVariableId &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
    
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @NumberOfMoves =  &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove &lt;br /&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
    &lt;span class="rem"&gt;-- SELECT @NumberOfDisks = COUNT(*) FROM Games.InstanceVariable &lt;br /&gt;-- WHERE InstanceId = @InstanceId&lt;/span&gt;
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @NumberOfDisks = VariableInstanceCount, @MaxMoves = &lt;br /&gt;(POWER(2,@NumberOfDisks) - 1) 
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.Instance
         &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
    
    
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @MinVariableId = &lt;span class="kwrd"&gt;MIN&lt;/span&gt;(InstanceVariableId) &lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceVariable
    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId

    &lt;span class="kwrd"&gt;IF&lt;/span&gt; @PostMoveCheck = 1
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @TwoMovesBackVariableId = InstanceVariableId
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove im 
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; MoveNumber = (@NumberOfMoves - 2)
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceId = @InstanceId
        
        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @LastMoveVariableId = InstanceVariableId
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; MoveNumber = @NumberOfMoves
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceId = @InstanceId
        
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
        
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @IsBigDiskOnLastPegYet &lt;span class="kwrd"&gt;BIT&lt;/span&gt; = 0
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @IsBigDiskOnLastPegYet = &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*)
        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceVariable
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceVariableNumber = @NumberOfDisks
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; VariableCurrentValue = 3
        &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceId = @InstanceId
        
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @NumberOfDisksOnLastPeg = &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceVariable 
    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId &lt;span class="kwrd"&gt;AND&lt;/span&gt; VariableCurrentValue = 3
    &lt;span class="rem"&gt;-- Check for moves less than 2 raised to number of disks and for all disks &lt;br /&gt;-- on the correct peg.  &lt;/span&gt;&lt;span class="rem"&gt;The rules function keeps disks from being put on in &lt;br /&gt;-- &lt;/span&gt;&lt;span class="rem"&gt;the wrong order.&lt;/span&gt;
    
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @NumberOfMovesLeft &lt;span class="kwrd"&gt;INT&lt;/span&gt; = @MaxMoves - @NumberOfMoves
    
    
    &lt;span class="kwrd"&gt;IF&lt;/span&gt;   @NumberOfMoves &amp;lt; POWER(2,@NumberOfDisks) 
    &lt;span class="kwrd"&gt;AND&lt;/span&gt; (@NumberOfDisksOnLastPeg = @NumberOfDisks)
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = 1&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @MidPointMoves &lt;span class="kwrd"&gt;INT&lt;/span&gt; = ((@MaxMoves + 1) /2)
        
        &lt;span class="kwrd"&gt;IF&lt;/span&gt; @NumberOfMoves &amp;gt; @MidPointMoves 
        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
            &lt;span class="kwrd"&gt;IF&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;EXISTS&lt;/span&gt; 
            (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 0 &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove im
                &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Games.InstanceVariable iv
                &lt;span class="kwrd"&gt;ON&lt;/span&gt; im.InstanceVariableId = iv.InstanceVariableId
                &lt;span class="kwrd"&gt;AND&lt;/span&gt; iv.InstanceVariableNumber = @NumberOfDisks
                &lt;span class="kwrd"&gt;AND&lt;/span&gt; im.InstanceVariableValue = 3
                &lt;span class="kwrd"&gt;AND&lt;/span&gt; im.MoveNumber = @MidPointMoves)
            &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; -1
            &lt;span class="kwrd"&gt;END&lt;/span&gt;
        &lt;span class="kwrd"&gt;END&lt;/span&gt;

        &lt;span class="kwrd"&gt;IF&lt;/span&gt;  
        (@NumberOfMoves + @NumberOfDisks - @NumberOfDisksOnLastPeg) &amp;gt; @MaxMoves
        &lt;span class="rem"&gt;-- @NumberOfMoves &amp;gt; POWER(2,@NumberOfDisks - @NumberOfDisksOnLastPeg) - 1&lt;/span&gt;
        &lt;span class="rem"&gt;-- Big diks must reach be on third peg by half of the remaining moves&lt;/span&gt;
        &lt;span class="kwrd"&gt;OR&lt;/span&gt; (@IsBigDiskOnLastPegYet = 0 &lt;span class="kwrd"&gt;AND&lt;/span&gt; @NumberOfMoves &amp;gt; &lt;br /&gt;(POWER(2,@NumberOfDisks)/2) -1)
        &lt;span class="rem"&gt;-- OR (@NumberOfMovesLeft &amp;gt; (POWER(2,@NumberOfDisks - @NumberOfDisksOnLastPeg) &lt;br /&gt;- POWER(2,@NumberOf))&lt;/span&gt;
        &lt;span class="rem"&gt;-- Every other move must be the smallest peg&lt;/span&gt;
         &lt;span class="kwrd"&gt;OR&lt;/span&gt; (@TwoMovesBackVariableId &amp;lt;&amp;gt; @LastMoveVariableId 
            &lt;span class="kwrd"&gt;AND&lt;/span&gt; @MinVariableId = @TwoMovesBackVariableId &lt;span class="kwrd"&gt;AND&lt;/span&gt; @PostMoveCheck =1)
        &lt;span class="rem"&gt;-- The big disk must move to the center peg at the midpoint of the game.&lt;/span&gt;

        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
            &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -1    
        &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; @ResultVar

END&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Ultimately, I’d like to eliminate the use of the functions altogether and “schematize” this.&amp;#160; That is, the rules and game status should be represent-able within a generic schema.&amp;#160; This would allow the user to be able to create any game through a generic interface rather than requiring the development of a function.&amp;#160; Based on the fact that the rules and status are completely based on states of entities and their inter-relationships, it should be possible to create a schema to represent this.&lt;/p&gt;

&lt;p&gt;Below are the functions used for the game move/game status.&amp;#160; Although these functions are specific to the game, they are defined at the game level and the intent is to execute them dynamically in the game engine based on the game selected.&amp;#160; Therefore, we are still able to have a generic framework for doing the game even though we have create domain-specific code.&lt;/p&gt;

&lt;p&gt;The below code does cheat a little bit – it has a couple of “hints” to prevent non-productive moves and terminate the game early.&amp;#160; For example, if the user doesn’t move (or can’t move) the bottom disk on the middle peg in the middle move, we know that the game is lost.&amp;#160; (we define losing as not solving the puzzle in the minimum moves).&amp;#160; We also don’t let the same move to be reversed, since again that means the optimal moves can’t be achieved.&amp;#160; These hints can be picked up through examining the winning pattern, and my&amp;#160; long-term goal is for these to be incorporated into the “hinting” aspect of the simulator rather than having to be defined ahead of time.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;REATE &lt;span class="kwrd"&gt;FUNCTION&lt;/span&gt; [Games].[fn_CheckHanoiMove]
(
    &lt;span class="rem"&gt;-- Add the parameters for the function here&lt;/span&gt;
    @InstanceId &lt;span class="kwrd"&gt;int&lt;/span&gt;,
    @VariableNumber &lt;span class="kwrd"&gt;int&lt;/span&gt;,
    @VariableValue &lt;span class="kwrd"&gt;int&lt;/span&gt;,
    @LastVariableNumber &lt;span class="kwrd"&gt;int&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    @OldVariableValue &lt;span class="kwrd"&gt;int&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    @PostCheck &lt;span class="kwrd"&gt;bit&lt;/span&gt; = 0
)
&lt;span class="kwrd"&gt;RETURNS&lt;/span&gt; &lt;span class="kwrd"&gt;INT&lt;/span&gt;
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="rem"&gt;-- Declare the return variable here&lt;/span&gt;
    &lt;span class="rem"&gt;-- 0 = Move Invalid&lt;/span&gt;
    &lt;span class="rem"&gt;-- -1 = Game over - out of moves&lt;/span&gt;
    &lt;span class="rem"&gt;-- 1 = Move Valid&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @ResultVar &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 1
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @NumberOfDisks &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0 

    &lt;span class="kwrd"&gt;IF&lt;/span&gt; @LastVariableNumber &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt; 1 @LastVariableNumber = InstanceVariableNumber 
            &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove im
            &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Games.InstanceVariable iv
            &lt;span class="kwrd"&gt;ON&lt;/span&gt; im.InstanceVariableId
            = iv.InstanceVariableId
            &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; im.InstanceId = @InstanceId
            &lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; MoveNumber &lt;span class="kwrd"&gt;DESC&lt;/span&gt;
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;IF&lt;/span&gt; @OldVariableValue &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @OldVariableValue = VariableCurrentValue &lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceVariable &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceVariableNumber = @VariableNumber
            &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceId = @InstanceId
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    
    &lt;span class="rem"&gt;-- Represents the peg that we were on before&lt;/span&gt;
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @NumberOfDisks = VariableInstanceCount &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.Instance &lt;br /&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
    
    &lt;span class="rem"&gt;-- Validate that there is not already a peg with the disk &lt;br /&gt;-- which is a lower number disk&lt;/span&gt;
    &lt;span class="rem"&gt;-- (Disks are numbered from 1 to N with 1 as the top disk)&lt;/span&gt;
    &lt;span class="kwrd"&gt;IF&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId) = (POWER(2,@NumberOfDisks) - 1 )
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; &lt;span class="rem"&gt;-- No more moves after this one&lt;/span&gt;
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -1
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;IF&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId) &amp;gt; (POWER(2,@NumberOfDisks) - 1 )
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; &lt;span class="rem"&gt;-- No more moves&lt;/span&gt;
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -6
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; &lt;br /&gt;&lt;span class="rem"&gt;-- Check that destination peg does not already have a smaller peg on it&lt;/span&gt;
        &lt;span class="kwrd"&gt;IF&lt;/span&gt; ((&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceVariable
                        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; VariableCurrentValue = @VariableValue
                          &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceVariableNumber&amp;lt; @VariableNumber
                          &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceId = @InstanceId) &amp;gt; 0)
        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
            &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -2 &lt;span class="rem"&gt;-- Destination peg has a bigger disk on it&lt;/span&gt;
        &lt;span class="kwrd"&gt;END&lt;/span&gt;
        
        &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; 
            &lt;span class="rem"&gt;-- Check that this disk was the top disk on the move-from peg&lt;/span&gt;
            &lt;span class="kwrd"&gt;IF&lt;/span&gt; ((&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceVariable
                        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceVariableNumber &amp;lt; @VariableNumber
                            &lt;span class="kwrd"&gt;AND&lt;/span&gt; VariableCurrentValue = @OldVariableValue
                            &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceId = @InstanceId) &amp;gt; 0)
            &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -3 &lt;br /&gt;&lt;span class="rem"&gt;-- Source peg had a smaller disk on it.&lt;/span&gt;
            &lt;span class="kwrd"&gt;END&lt;/span&gt;
            &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                &lt;span class="kwrd"&gt;IF&lt;/span&gt; (@VariableValue = @OldVariableValue)
                &lt;span class="rem"&gt;-- Move must change the position&lt;/span&gt;
                &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                    &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -4 &lt;span class="rem"&gt;-- Disk moved to same peg&lt;/span&gt;
                &lt;span class="kwrd"&gt;END&lt;/span&gt;
                &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                    &lt;span class="kwrd"&gt;IF&lt;/span&gt; (@LastVariableNumber = @VariableNumber &lt;span class="kwrd"&gt;AND&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;br /&gt;&lt;/span&gt; @LastVariableNumber &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;)
                    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                    &lt;span class="rem"&gt;-- Don't allow nonsense move &lt;br /&gt;-- Moved same piece twice in a row &lt;/span&gt;
                        &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -5
                    &lt;span class="kwrd"&gt;END&lt;/span&gt;
                    &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                        
                        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @NumberOfMoves &lt;span class="kwrd"&gt;INT&lt;/span&gt; = 0
                        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @NumberOfMoves =  &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; Games.InstanceMove &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
                        &lt;span class="kwrd"&gt;IF&lt;/span&gt; @PostCheck = 0 &lt;span class="rem"&gt;-- For pre-check, &lt;br /&gt;-- increment by one so we are on the right move&lt;/span&gt;
                        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                            &lt;span class="kwrd"&gt;SET&lt;/span&gt; @NumberOfMoves = @NumberOfMoves + 1
                        &lt;span class="kwrd"&gt;END&lt;/span&gt;
    
                        &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @MidPointMoves &lt;span class="kwrd"&gt;INT&lt;/span&gt; = &lt;br /&gt;POWER(2,@NumberOfDisks) / 2
        
                        &lt;span class="kwrd"&gt;IF&lt;/span&gt; @NumberOfMoves = @MidPointMoves 
                            &lt;span class="kwrd"&gt;AND&lt;/span&gt; (@VariableNumber &amp;lt;&amp;gt; @NumberOfDisks &lt;br /&gt;&lt;span class="kwrd"&gt;OR&lt;/span&gt; @VariableVAlue &amp;lt;&amp;gt; 3)
                        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
                        &lt;span class="rem"&gt;-- Only valid move here is the big disk to last peg&lt;/span&gt;
                            &lt;span class="kwrd"&gt;SET&lt;/span&gt; @ResultVar = -7
                        &lt;span class="kwrd"&gt;END&lt;/span&gt;
                    &lt;span class="kwrd"&gt;END&lt;/span&gt;
                &lt;span class="kwrd"&gt;END&lt;/span&gt;
            &lt;span class="kwrd"&gt;END&lt;/span&gt; 
        &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;END&lt;/span&gt;

    &lt;span class="rem"&gt;-- Return the result of the function&lt;/span&gt;
    &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; @ResultVar

END&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Regarding these functions,&amp;#160; with the exception of the Tower of Hanoi rule check, which we can easily convert to a generic fashion by storing the function name in the game row representing Hanoi and using dynamic SQL, all of the code is generic and not specific to any particular type of game.&amp;#160; Let’s take a look at the Windows form used to play the game and play it for a simple 2 disk scenario using brute force. In this scenario, we only “lose” the game once before having to backup.&amp;#160; You’ll see as we increase the number of disks on the below graphics, that the loss rate increases very rapidly for games with higher number of disks.&lt;/p&gt;

&lt;p&gt;&amp;#160; &lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image1.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image1_thumb.png" width="541" height="398" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;At this point, we now have an interface that allows us to play a game (although it is somewhat tailored to Hanoi and requires a little bit more work to make truly generic) and record the results in state data. Given the above input along with the trigger interaction, here is the data generated including the states of the disks and the pegs as well as overall game states using various variable configuration (2 disks, 3 disks, etc.).&amp;#160; Note the patterns.&amp;#160; The domain states refer to which variable was moved on a move and the range states indicate which peg was altered for a move.&amp;#160; For example for the 2-disk scenario, on Move 1, we moved Disk 1 to Peg 3, On Move 2, we moved Disk 2 to Peg 3 and on Move 3, we moved Disk 1 to Peg 3.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image2_thumb.png" width="548" height="196" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image6.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image6_thumb.png" width="552" height="369" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image10.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/microsoftbob/WindowsLiveWriter/Softwarewritingsoftware_D50D/image10_thumb.png" width="547" height="374" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Above are the results of 3 to 5 disk scenarios.&amp;#160; Remember, the game is being solved through brute-force at this point.&amp;#160; We are just trying to simulate different variations in order to find a pattern or general algorithm for solving the game.&amp;#160; All the application understands is how to call a stored procedure to make a rule based on another stored procedure that provides a list of all the legal rules, another procedure to find out the status and determine if a game is still winnable or if it has been won, and finally a stored procedure that can be called to back out a move and try again without having to start all over.&amp;#160; Somewhere in the list is the required rule, as there is only 1 “winning” solution to any Hanoi game that uses the fewest moves.&amp;#160; Using this approach, along with adding a couple of hints to prevent obvious dead-ends game-plays or detect losses half-way through, we can practically simulate up to 6 disks before the time complexity involved with the recursive depth-searches becomes overwhelming.&lt;/p&gt;

&lt;p&gt;Below is the main code in the c# program for playing the game.&amp;#160; As you can see, there is nothing specific to Hanoi, this could be used to try to play any game and find the solution by brute force. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; MoveStatus(fn_GetValidHanoiMoves_View move, &lt;span class="kwrd"&gt;bool&lt;/span&gt; used)
        {
            Move = move;
            Used = used;
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;







.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; List&amp;lt;MoveStatus&amp;gt; getMoveStatuses(&lt;span class="kwrd"&gt;int&lt;/span&gt; instanceId)
        {
            List&amp;lt;MoveStatus&amp;gt; moveStatuses = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;MoveStatus&amp;gt;();
            {
                var gameMoves = from p &lt;span class="kwrd"&gt;in&lt;/span&gt; _dc.fn_GetValidHanoiMoves(instanceId)
                                select p;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (fn_GetValidHanoiMoves_View gameMove &lt;span class="kwrd"&gt;in&lt;/span&gt; gameMoves)
                {
                    &lt;span class="rem"&gt;// Add them to the list&lt;/span&gt;
                    moveStatuses.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; MoveStatus(gameMove, &lt;span class="kwrd"&gt;false&lt;/span&gt;));
                }
                &lt;span class="rem"&gt;//_dc.SubmitChanges();&lt;/span&gt;
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; moveStatuses;
        }


        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; move(List&amp;lt;MoveStatus&amp;gt; moveStatuses)
        {
            &lt;span class="kwrd"&gt;int&lt;/span&gt;? gameStatus = 0;
            Stack&amp;lt;List&amp;lt;MoveStatus&amp;gt;&amp;gt; moveStack = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stack&amp;lt;List&amp;lt;MoveStatus&amp;gt;&amp;gt;();
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (gameStatus != 1)
            {
                &lt;span class="rem"&gt;// Create a new list on the stack unless we are in undo mode&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (moveStack.Count() &amp;gt;= Math.Pow(2.00, &lt;br /&gt;(&lt;span class="kwrd"&gt;float&lt;/span&gt;)&lt;span class="kwrd"&gt;this&lt;/span&gt;.numericUpDownObjects.Value))
                {
                    &lt;span class="rem"&gt;// Went too far, roll back the stack&lt;/span&gt;
                    _dc.UndoLastMove(_InstanceId);
                    moveStatuses = moveStack.Pop();
                }
                &lt;span class="kwrd"&gt;bool&lt;/span&gt; madeMove = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
                &lt;span class="rem"&gt;// Try a move until one works&lt;/span&gt;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MoveStatus moveStatus &lt;span class="kwrd"&gt;in&lt;/span&gt; moveStatuses)
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!moveStatus.Used)
                    {
                        &lt;span class="kwrd"&gt;int&lt;/span&gt;? lastMoveId = 0;
                        moveStatus.Used = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                        _attempts++;
                        _dc.InsertInstanceMove(&lt;span class="kwrd"&gt;ref&lt;/span&gt; lastMoveId, &lt;span class="kwrd"&gt;ref&lt;/span&gt; gameStatus, &lt;br /&gt;_InstanceId,
                            moveStatus.Move.InstanceVariableId,
                            moveStatus.Move.InstanceVariableValue);
                        &lt;span class="kwrd"&gt;this&lt;/span&gt;.listBox1.Items.Add(&lt;span class="str"&gt;&amp;quot;Move &amp;quot;&lt;/span&gt; + &lt;br /&gt;moveStatus.Move.InstanceVariableNumber.ToString() +&lt;br /&gt;                            &lt;span class="str"&gt;&amp;quot; to &amp;quot;&lt;/span&gt; &lt;br /&gt;+ moveStatus.Move.InstanceVariableValue.ToString() &lt;/pre&gt;

&lt;pre class="csharpcode"&gt;+ &lt;span class="str"&gt;&amp;quot;; stack=&amp;quot;&lt;/span&gt; + moveStack.Count().ToString());
                        _dc.SubmitChanges();
                        &lt;span class="rem"&gt;// if move fails, undo it.&lt;/span&gt;
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (gameStatus == -1)
                        {
                            _losses++;

                            _dc.UndoLastMove(_InstanceId);
                            &lt;span class="kwrd"&gt;this&lt;/span&gt;.listBox1.Items.Add(&lt;span class="str"&gt;&amp;quot;Undo; stack=&amp;quot;&lt;/span&gt; &lt;br /&gt;+ moveStack.Count().ToString());
                            _dc.SubmitChanges();
                        }
                        &lt;span class="rem"&gt;// If move was ok or game-won then break out&lt;/span&gt;
                        &lt;span class="kwrd"&gt;else&lt;/span&gt;
                        {
                            madeMove = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                        }
                    }
                }
                &lt;span class="rem"&gt;// If a move worked, we can move on, else we need to backtrack&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (gameStatus == 0 &amp;amp;&amp;amp; madeMove)
                {
                    moveStack.Push(moveStatuses);
                    moveStatuses = (getMoveStatuses(_InstanceId.Value));
                }
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (gameStatus == -1 || !madeMove || moveStatuses.Count()== 0)
                {
                    &lt;span class="rem"&gt;// If game status is loosing, or we weren't able to make &lt;br /&gt;// a move&lt;/span&gt;
                    &lt;span class="rem"&gt;// or the move status count (generated in line just above)&lt;/span&gt;
                    &lt;span class="rem"&gt;// is 0, then we undo and pop the stack back.&lt;/span&gt;
                    _dc.UndoLastMove(_InstanceId);
                    &lt;span class="kwrd"&gt;this&lt;/span&gt;.listBox1.Items.Add(&lt;span class="str"&gt;&amp;quot;Undo; stack=&amp;quot;&lt;/span&gt; &lt;br /&gt;+ moveStack.Count().ToString());
                    _dc.SubmitChanges();
                    moveStatuses = (moveStack.Pop()); &lt;br /&gt;&lt;span class="rem"&gt;// Go back to the prior move statuses&lt;/span&gt;
                }
            }
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;







.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Let’s take a closer look at domain states and range states to understand their significance:&lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="0" width="524"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="26"&gt;
        &lt;p&gt;&lt;font size="1"&gt;Disks&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;DomainStates&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;RangeStates&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="26"&gt;
        &lt;p&gt;&lt;font size="1"&gt;2&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;1,2,1&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;2,3,3&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="26"&gt;
        &lt;p&gt;&lt;font size="1"&gt;3&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;1,2,1,3,1,2,1&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;3,2,2,3,1,3,3&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="26"&gt;
        &lt;p&gt;&lt;font size="1"&gt;4&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;1,2,1,3,1,2,1,4,1,2,1,3,1,2,1&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;2,3,3,2,1,2,2,3,3,1,1,3,2,3,3&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="26"&gt;
        &lt;p&gt;&lt;font size="1"&gt;5&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td width="248"&gt;
        &lt;p&gt;&lt;font size="1"&gt;3,2,2,3,1,3,3,2,2,1,1,2,3,2,2,3,1,3,3,1,2,1,1,3,3,2,2,3,1,3,3&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Based on the patterns and their interrelationships, we can determine what a solution would be for N disks through some mathematical introspection.&amp;#160; We should be able to do this generically in code.&amp;#160; For example, note that where N is the number of disks, N is always moved on the T/2 moves where T is the total number of moves required for the optimal solution.&amp;#160; Note also that there is symmetry in the domain states before and after the middle move – i.e. for disk-2 scenario, the same disk is moved on the first and final third move, for 3-disk scenario, we have 1,2,1, both before and after the middle-move and this pattern continues for the 4 and 5 disk scenarios.&amp;#160; Thus we can generate a hint for an optimal solution to automatically replay the first half of the game when trying to solve for a greater number of disks.&amp;#160; There are additional patterns in the range states and how they relate to the domains.&amp;#160; By simply finding all of the patterns, one should be able to define the winning pattern for any number of disks without even knowing the recurrence relation.&amp;#160; &lt;/p&gt;

&lt;p&gt;Another way to look at this is from the point of view of the variable states, which my infrastructure provides through the code previously shown in the trigger.&amp;#160; It just involves appending a 1 or 0 on to the bit mask based on whether or not the variable was affected.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.InstanceVariableValueStates
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; MoveStates = &lt;span class="kwrd"&gt;COALESCE&lt;/span&gt;(MoveStates,&lt;span class="str"&gt;''&lt;/span&gt;) + &lt;span class="str"&gt;'1'&lt;/span&gt;
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceVariableNumber = @InstanceVariableNumber
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceVariableValue= @InstanceVariableValue
         
        &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; Games.InstanceVariableValueStates
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; MoveStates = &lt;span class="kwrd"&gt;COALESCE&lt;/span&gt;(MoveStates,&lt;span class="str"&gt;''&lt;/span&gt;) + &lt;span class="str"&gt;'0'&lt;/span&gt;
        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; InstanceId = @InstanceId
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; (InstanceVariableNumber = @InstanceVariableNumber
         &lt;span class="kwrd"&gt;AND&lt;/span&gt; InstanceVariableValue= @InstanceVariableValue)&lt;/pre&gt;
&lt;style type="text/css"&gt;








.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;At the end of the game, we end up with the following.&amp;#160; the bit mask just indicates what move the disk is moved to a particular peg. For example in instance 200, the 3 disk game, we find that disk 2 is moved onto disk 3 on the second move.&lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="0" width="428"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;Instance&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;Variable&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;Value&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;&lt;em&gt;Bit Mask (each bit is a move, and a 1 indicate a pairing of the variable (disk) and the value (peg).&lt;/em&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;199&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000 - Disk 1 never moved to peg 1 (started there, but never moved there)&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;199&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;&lt;font color="#ff0000" size="2"&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;&lt;font color="#ff0000" size="2"&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;&lt;font size="2"&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;1&lt;/font&gt;00 &lt;/strong&gt;- &lt;font color="#ff0000"&gt;&lt;strong&gt;Disk 1 moved to disk 2 on move 1&lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;199&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;&lt;font color="#ff0000"&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;&lt;font color="#ff0000"&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;&lt;strong&gt;00&lt;font color="#ff0000"&gt;1&lt;/font&gt; - &lt;font color="#ff0000"&gt;Disk 1 moved to disk 3 on move 3 (last move)&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;199&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;199&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;199&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;2&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;3&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;&lt;font color="#000000"&gt;0&lt;font color="#ff0000"&gt;1&lt;/font&gt;0&lt;/font&gt;– Disk 2 moved onto peg 3 on move 2&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000100&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0010000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;1000001&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0100000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000010&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;200&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0001000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000010000010000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;100000100000100&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;001000001000001&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000100000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000001000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;010000000000010&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000100000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000001000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;201&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000010000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000100000100000100000100000100&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0010000010000010000010000010000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;1000001000001000001000001000001&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000001000000000001000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0100000000000100000000000100000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000010000000000010000000000010&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000000000000000100000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000000010000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0001000000000000000000000001000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000100000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000000000000000000010000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;5&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;5&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;202&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;5&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;0000000000000001000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000010000010000010000010000010000010000010000010000010000010000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;100000100000100000100000100000100000100000100000100000100000100&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;001000001000001000001000001000001000001000001000001000001000001&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000100000000000100000000000100000000000100000000000100000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000001000000000001000000000001000000000001000000000001000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;010000000000010000000000010000000000010000000000010000000000010&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000010000000000000000000000010000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000100000000000000000000000100000000000000000000000100000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000001000000000000000000000001000000000000000000000001000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000000000000000000000000100000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000000001000000000000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000010000000000000000000000000000000000000000000000010000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;5&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000000000000000000000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;5&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000100000000000000000000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;5&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000000000000000000000000000000001000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;6&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000000000000000000000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;6&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;2&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000000000000000000000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="60"&gt;
        &lt;p&gt;203&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="48"&gt;
        &lt;p&gt;6&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="45"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="273"&gt;
        &lt;p&gt;000000000000000000000000000000010000000000000000000000000000000&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Examining these patterns bit-by-bit for shift operations, power-functions, etc, may be a more practical way to decipher the winning patterns:&lt;/p&gt;

&lt;p&gt;My goal is that the code should be able to find patterns, store the patterns in a dictionary and then consult a dictionary of patterns learned over time including patterns related to how to learn, match it up to the states based on how the variables change, and identify a recursive relation to solve for future games, not by using brute force, but by using the learned rules.&amp;#160; As time goes on, we can add to the dictionary new algorithms and then use them to look for patterns.&amp;#160; Therefore, this can be the basis for an extensible/self-learning framework.&lt;/p&gt;

&lt;p&gt;Now, that we have captured the data states of the game, we can examine the game states as they relate to the number of variables.&amp;#160; The engine for examining and learning the patterns can be the same engine that does the simulation, thus this can be a recursive self-learning organism feeding off of achieving goals within the constraints of rules.&amp;#160;&amp;#160; We should be able to apply this technique to any scenario, including complex ones by schematizing the scenario into a game-based schema.&amp;#160;&amp;#160; Since we can do that for Hanoi, although this is a very simple case, my thesis is that the same fundamental approach can be used for other scenarios, which may be much more complex.&lt;/p&gt;

&lt;p&gt;I apologize that some of the code isn’t formatted nicely and wrapped strangely in some places.&amp;#160; I used a handy add-in for inserting code (Insert Code from &lt;a title="http://www.shahine.com/omar/InsertCodeForWindowsLiveWriter.aspx" href="http://www.shahine.com/omar/InsertCodeForWindowsLiveWriter.aspx"&gt;http://www.shahine.com/omar/InsertCodeForWindowsLiveWriter.aspx&lt;/a&gt;), but some of my code lines are too long and got truncated.&amp;#160; Due to time constraints, I just went in and put hard returns where necessary in the blog post to make sure everything at least displays on the page. &lt;/p&gt;

&lt;p&gt;If you feel like I left you hanging, it’s because I did.&amp;#160; I will have more to post on this later after I figure out the recognition piece.&amp;#160; Stay tuned…&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:c83e803b-9f45-4e00-af23-0d5b12e556b0" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/AI" rel="tag"&gt;AI&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Artificial+Intelligence" rel="tag"&gt;Artificial Intelligence&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Simulation" rel="tag"&gt;Simulation&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SQL+Server" rel="tag"&gt;SQL Server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Visual+Studio+.NET" rel="tag"&gt;Visual Studio .NET&lt;/a&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9824656" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Artificial+Intelligence/default.aspx">Artificial Intelligence</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Simulation/default.aspx">Simulation</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/Software+Automation/default.aspx">Software Automation</category><category domain="http://blogs.msdn.com/microsoftbob/archive/tags/AI/default.aspx">AI</category></item><item><title>Generating a List of Calendar Dates</title><link>http://blogs.msdn.com/microsoftbob/archive/2009/07/06/generating-a-list-of-calendar-dates.aspx</link><pubDate>Mon, 06 Jul 2009 05:25:26 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9818500</guid><dc:creator>Bob Leithiser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/microsoftbob/comments/9818500.aspx</comments><wfw:commentRss>http://blogs.msdn.com/microsoftbob/commentrss.aspx?PostID=9818500</wfw:commentRss><wfw:comment>http://blogs.msdn.com/microsoftbob/rsscomments.aspx?PostID=9818500</wfw:comment><description>&lt;p&gt;For today, here’s a simple trick.&amp;#160; Ever need to get a list of all the calendar dates for a period?&amp;#160; This is very simple using a user defined function with a table.&amp;#160;&amp;#160; Below is a simple version.&amp;#160; I have a more complex version I am using for my application that filters based on another table containing holidays, etc.&amp;#160; &lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- =============================================&lt;/span&gt;
&lt;span class="rem"&gt;-- Author:        Bob Leithiser&lt;/span&gt;
&lt;span class="rem"&gt;-- Create date: 7/5/2009&lt;/span&gt;
&lt;span class="rem"&gt;-- Description:    Return a list of dates in table format for a specified date range&lt;/span&gt;
&lt;span class="rem"&gt;-- =============================================&lt;/span&gt;
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;FUNCTION&lt;/span&gt; [Util].[udf_GetCalendarDates]
(
    @StartDate &lt;span class="kwrd"&gt;DATE&lt;/span&gt;, 
    @EndDate &lt;span class="kwrd"&gt;DATE&lt;/span&gt;
)
&lt;span class="kwrd"&gt;RETURNS&lt;/span&gt; 
@CalendarDates &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; 
(
    &lt;span class="rem"&gt;-- Add the column definitions for the TABLE variable here&lt;/span&gt;
    CalendarDate &lt;span class="kwrd"&gt;DATE&lt;/span&gt;
)
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="rem"&gt;-- Fill the table variable with the rows for your result set&lt;/span&gt;
    &lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @CalendarDate &lt;span class="kwrd"&gt;DATE&lt;/span&gt; = @StartDate
    &lt;span class="kwrd"&gt;WHILE&lt;/span&gt; @CalendarDate  &amp;lt;= @EndDate
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
            INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @CalendarDates (CalendarDate) &lt;span class="kwrd"&gt;VALUES&lt;/span&gt; (@CalendarDate)
        &lt;span class="kwrd"&gt;END&lt;/span&gt;
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; @CalendarDate = DATEADD(DD,1,@CalendarDate)
    &lt;span class="kwrd"&gt;END&lt;/span&gt;
    &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; 
&lt;span class="kwrd"&gt;END&lt;/span&gt;

&lt;span class="kwrd"&gt;GO&lt;/span&gt;


&lt;span class="kwrd"&gt;select&lt;/span&gt; * &lt;span class="kwrd"&gt;from&lt;/span&gt; util.udf_GetCalendarDates(&lt;span class="str"&gt;'20090101'&lt;/span&gt;,&lt;span class="str"&gt;'20090130'&lt;/span&gt;)&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;and now we get:&lt;/pre&gt;

&lt;p&gt;CalendarDate 
  &lt;br /&gt;2009-01-01 

  &lt;br /&gt;2009-01-02 

  &lt;br /&gt;2009-01-03 

  &lt;br /&gt;2009-01-04 

  &lt;br /&gt;2009-01-05 

  &lt;br /&gt;2009-01-06 

  &lt;br /&gt;2009-01-07 

  &lt;br /&gt;2009-01-08 

  &lt;br /&gt;2009-01-09 

  &lt;br /&gt;2009-01-10 

  &lt;br /&gt;2009-01-11 

  &lt;br /&gt;2009-01-12 

  &lt;br /&gt;2009-01-13 

  &lt;br /&gt;2009-01-14 

  &lt;br /&gt;2009-01-15 

  &lt;br /&gt;2009-01-16 

  &lt;br /&gt;2009-01-17 

  &lt;br /&gt;2009-01-18 

  &lt;br /&gt;2009-01-19 

  &lt;br /&gt;2009-01-20 

  &lt;br /&gt;2009-01-21 

  &lt;br /&gt;2009-01-22 

  &lt;br /&gt;2009-01-23 

  &lt;br /&gt;2009-01-24 

  &lt;br /&gt;2009-01-25 

  &lt;br /&gt;2009-01-26 

  &lt;br /&gt;2009-01-27 

  &lt;br /&gt;2009-01-28 

  &lt;br /&gt;2009-01-29 

  &lt;br /&gt;2009-01-30&lt;/p&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Here’s an example where I found this useful.&amp;#160; I needed to generate a list of holidays to avoid processing of days not containing any business activity data as part of an analytic/simulation application.&amp;#160; &lt;/p&gt;

&lt;pre class="csharpcode"&gt;insert &lt;span class="kwrd"&gt;into&lt;/span&gt; &lt;span class="kwrd"&gt;Load&lt;/span&gt;.Holiday (ExchangeName,HolidayDate)
&lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="str"&gt;'*'&lt;/span&gt;, CalendarDate
&lt;span class="kwrd"&gt;from&lt;/span&gt; util.udf_GetCalendarDates(&lt;span class="str"&gt;'2007-05-01'&lt;/span&gt;,&lt;span class="str"&gt;'2009-07-04'&lt;/span&gt;)
&lt;span class="kwrd"&gt;where&lt;/span&gt; &lt;span class="kwrd"&gt;not&lt;/span&gt; &lt;span class="kwrd"&gt;exists&lt;/span&gt;
(&lt;span class="kwrd"&gt;select&lt;/span&gt; &lt;span class="kwrd"&gt;distinct&lt;/span&gt; marketdate &lt;span class="kwrd"&gt;from&lt;/span&gt; dbo.EquityHistory &lt;span class="kwrd"&gt;where&lt;/span&gt; MarketDate = CalendarDate )
&lt;span class="kwrd"&gt;and&lt;/span&gt; DATEPART(WEEKDAY,CalendarDate) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;IN&lt;/span&gt; (1,7)&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;select * from Load.holiday&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;(20 row(s) affected)&lt;/p&gt;

&lt;p&gt;ExchangeName&amp;#160;&amp;#160;&amp;#160; HolidayDate
  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2007-05-28

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2007-07-04

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2007-09-03

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2007-11-22

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2007-12-25

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-01-01

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-01-21

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-02-18

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-03-21

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-05-26

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-07-04

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-09-01

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-11-27

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2008-12-25

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2009-01-01

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2009-01-19

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2009-02-16

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2009-04-10

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2009-05-25

  &lt;br /&gt;*&amp;#160;&amp;#160;&amp;#160; 2009-07-03&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9818500" width="1" height="1"&gt;</description></item></channel></rss>