<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.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>Alberto Ferrari</title><link>http://sqlblog.com/blogs/alberto_ferrari/default.aspx</link><description /><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Remote Execution of SSIS Packages</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2009/12/02/remote-execution-of-ssis-packages.aspx</link><pubDate>Wed, 02 Dec 2009 14:28:25 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:19414</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>10</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/19414.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=19414</wfw:commentRss><description>Having the need to execute a package on a remote server, I discovered&amp;#160; that DtExec has no option to launch the package remotely (something that everybody apart me already knew…). So… time to write some code. I wrote a WCF Service that executes a...(&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/archive/2009/12/02/remote-execution-of-ssis-packages.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=19414" width="1" height="1"&gt;</description></item><item><title>SqlBulkCopy Performance Analysis</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2009/11/30/sqlbulkcopy-performance-analysis.aspx</link><pubDate>Mon, 30 Nov 2009 14:24:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:19323</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>6</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/19323.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=19323</wfw:commentRss><description>In the endless search for optimal performance in Bulk loading data, I have written a paper which describes how to reach top performance using the SqlBulkCopy class in .NET, trying to find the best combination of its parameter settings to load heaps, clustered...(&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/archive/2009/11/30/sqlbulkcopy-performance-analysis.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=19323" width="1" height="1"&gt;</description></item><item><title>DrillThrough Actions and (semi) Security in SSAS OLAP cubes</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2009/06/24/drillthrough-actions-and-semi-security-in-ssas-olap-cubes.aspx</link><pubDate>Wed, 24 Jun 2009 15:52:11 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:14896</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>1</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/14896.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=14896</wfw:commentRss><description>Using SSAS 2005/2008, there is no way to apply security to DRILLTHROUGH actions, so we cannot decide whether a specific user is authorized or not to perform a specific action. This is a “by design” behavior, since DRILLTHROUGH actions are initiated at...(&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/archive/2009/06/24/drillthrough-actions-and-semi-security-in-ssas-olap-cubes.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=14896" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSAS/default.aspx">SSAS</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Security/default.aspx">Security</category></item><item><title>Does SSIS knows how to sort a flow of data? Well… no</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/20/does-ssis-knows-how-to-sort-a-flow-of-data-well-no.aspx</link><pubDate>Mon, 20 Apr 2009 10:52:27 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:13376</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>12</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/13376.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=13376</wfw:commentRss><description>&lt;p&gt;Today I ran into a nice misfeature of SSIS that worths sharing.&lt;/p&gt;  &lt;p&gt;If I want to use SSIS to sort a flow of data, containing both lowecase and uppercase strings, I would expect a standard behaviour or, at least, something with some “common sense”. As I am going to show, the final result is completely nonsense and will lead to incorrect computations.&lt;/p&gt;  &lt;p&gt;Let us start with some information that I remember from the old time of ASCII code. Uppercase letters appears before the lowercase ones in the standard ASCII sequence and hence are sorted before them. Is it still true in the 2009 world with Unicode and all our new and fancy ways of storing strings? It seems so, if you run this simple VB script:&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 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:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;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:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;If&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;A&amp;quot;&lt;/span&gt; &amp;gt;= &lt;span style="color:#006080;"&gt;&amp;quot;a&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Then&lt;/span&gt;
    MsgBox(&lt;span style="color:#006080;"&gt;&amp;quot;A is greater or equal than a&amp;quot;&lt;/span&gt;)
&lt;span style="color:#0000ff;"&gt;Else&lt;/span&gt;
    MsgBox(&lt;span style="color:#006080;"&gt;&amp;quot;A is less than a&amp;quot;&lt;/span&gt;)
&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; If&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;You will get the correct result: uppercase comes BEFORE lowercase characters. So, since SSIS sort component does not provide any “consider/ignore case” checkbox, it has two options for sorting strings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It ignores casing and sorts data like SQL does. &lt;/li&gt;

  &lt;li&gt;It adhere to the standard sorting sequence and sorts uppercase BEFORE lowercase. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, armed with all this powerful knowledge, we can build a simpe package that receives three rows from this query:&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 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:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;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:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Name = &lt;span style="color:#006080;"&gt;'ALBERTO'&lt;/span&gt;, Surname = &lt;span style="color:#006080;"&gt;'FERRARI'&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;UNION&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;ALL&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Name = &lt;span style="color:#006080;"&gt;'alberto'&lt;/span&gt;, Surname = &lt;span style="color:#006080;"&gt;'ferrari'&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;UNION&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;ALL&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Name = &lt;span style="color:#006080;"&gt;'alberto'&lt;/span&gt;, Surname = &lt;span style="color:#006080;"&gt;'FERRARI'&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Then it sends them into a Sort by Name, Surname and add a data viewer after the SORT, just to check what the component does:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/image_24472200.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://sqlblog.com/blogs/alberto_ferrari/image_thumb_2D07047F.png" width="152" height="274" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I have been amazed to look at the data viewer:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/image_6BF8851A.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://sqlblog.com/blogs/alberto_ferrari/image_thumb_7FA56EAE.png" width="293" height="224" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;SSIS believes that lowercase strings should be LESS than uppercase ones and produces a reverse sorted list of rows. This is pretty important because, if after the flow you trust data to be sorted, your system will fail, as it has been the case with some code I received to test just today.&lt;/p&gt;

&lt;p&gt;The final lesson is pretty simple: do not trust common sense, for some (very) obscure reason the SSIS team decided to provide “Yet Another Sorting Method” to the IT World, generating some more confusion in the head of the poor SSIS programmer.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Does SSIS knows how to sort a flow of data? Well… no&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Does SSIS knows how to sort a flow of data? Well… no%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/20/does-ssis-knows-how-to-sort-a-flow-of-data-well-no.aspx" target="_blank" title = "Email Does SSIS knows how to sort a flow of data? Well… no"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/20/does-ssis-knows-how-to-sort-a-flow-of-data-well-no.aspx&amp;amp;title=Does+SSIS+knows+how+to+sort+a+flow+of+data%3f+Well%e2%80%a6+no" target="_blank" title = "Submit Does SSIS knows how to sort a flow of data? Well… no to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/20/does-ssis-knows-how-to-sort-a-flow-of-data-well-no.aspx&amp;amp;phase=2" target="_blank" title = "Submit Does SSIS knows how to sort a flow of data? Well… no to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/20/does-ssis-knows-how-to-sort-a-flow-of-data-well-no.aspx&amp;amp;title=Does+SSIS+knows+how+to+sort+a+flow+of+data%3f+Well%e2%80%a6+no" target="_blank" title = "Submit Does SSIS knows how to sort a flow of data? Well… no to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/20/does-ssis-knows-how-to-sort-a-flow-of-data-well-no.aspx&amp;amp;title=Does+SSIS+knows+how+to+sort+a+flow+of+data%3f+Well%e2%80%a6+no" target="_blank" title = "Submit Does SSIS knows how to sort a flow of data? Well… no to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/20/does-ssis-knows-how-to-sort-a-flow-of-data-well-no.aspx&amp;amp;title=Does+SSIS+knows+how+to+sort+a+flow+of+data%3f+Well%e2%80%a6+no&amp;amp;;top=1" target="_blank" title = "Add Does SSIS knows how to sort a flow of data? Well… no to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=13376" width="1" height="1"&gt;</description></item><item><title>European PASS 2009</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/16/european-pass-2009.aspx</link><pubDate>Thu, 16 Apr 2009 19:13:53 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:13336</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>1</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/13336.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=13336</wfw:commentRss><description>&lt;p&gt;Guys, I’m excited of being a speaker at &lt;span style="font-family:'Calibri','sans-serif';"&gt;&lt;font size="3"&gt;the &lt;/font&gt;&lt;a href="http://www.european-pass-conference.com/"&gt;&lt;font color="#800080" size="3"&gt;European PASS Conference 2009&lt;/font&gt;&lt;/a&gt;&lt;font size="3"&gt; (April 22-24, 2009 - Neuss, Germany).&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:'Calibri','sans-serif';"&gt;&lt;font size="3"&gt;I will present three sessions, on Slowly Changing Dimension Handling, OLAP partitioning with SSIS and scripts and, most interesting (at least for me), the &lt;a target="_blank"&gt;SQLBI Methodology&lt;/a&gt; with &lt;a href="http://sqlblog.com/blogs/marco_russo/" target="_blank"&gt;Marco Russo&lt;/a&gt;.&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:'Calibri','sans-serif';"&gt;&lt;font size="3"&gt;If you are going to attend the meeting and want to share a beer and some chat, you’ll be welcome!&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:'Calibri','sans-serif';"&gt;&lt;font size="3"&gt;See you.&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:'Calibri','sans-serif';"&gt;&lt;font size="3"&gt;Alberto&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=European PASS 2009&amp;amp;body=Seen on SQLblog.com: %0A%0A%09European PASS 2009%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/16/european-pass-2009.aspx" target="_blank" title = "Email European PASS 2009"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/16/european-pass-2009.aspx&amp;amp;title=European+PASS+2009" target="_blank" title = "Submit European PASS 2009 to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/16/european-pass-2009.aspx&amp;amp;phase=2" target="_blank" title = "Submit European PASS 2009 to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/16/european-pass-2009.aspx&amp;amp;title=European+PASS+2009" target="_blank" title = "Submit European PASS 2009 to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/16/european-pass-2009.aspx&amp;amp;title=European+PASS+2009" target="_blank" title = "Submit European PASS 2009 to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/04/16/european-pass-2009.aspx&amp;amp;title=European+PASS+2009&amp;amp;;top=1" target="_blank" title = "Add European PASS 2009 to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=13336" width="1" height="1"&gt;</description></item><item><title>SSAS: Reference materialized dimension might produce incorrect results</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/25/ssas-reference-materialized-dimension-might-produce-incorrect-results.aspx</link><pubDate>Wed, 25 Feb 2009 13:59:37 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:12198</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>9</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/12198.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=12198</wfw:commentRss><description>&lt;p&gt;Reference dimensions let you create a relationship between a measure group and a dimension using an intermediate dimension to act as a bridge between them. In the Adventure Works demo, for example, they are used to link reseller sales and orders to the geography dimension.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/mg_1C6268BC.png"&gt;&lt;img title="mg" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="254" alt="mg" src="http://sqlblog.com/blogs/alberto_ferrari/mg_thumb_64EC31C0.png" width="482" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Now, something that is less evident is how this specific kind of relationship is handled by SSAS. Let us look further in the definition of the relationship:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/mat_35BA4629.png"&gt;&lt;img title="mat" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="383" alt="mat" src="http://sqlblog.com/blogs/alberto_ferrari/mat_thumb_4DFD3A77.png" width="644" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;If the relationship is not materialized (something SSAS will dislike) then the relationship will be resolved during query time, with slow performances. Nevertheless, everything will work fine.&lt;/p&gt;  &lt;p&gt;If, on the other hand, we follow SSAS suggestion and decide to materialize it, we will need to understand what is going on under the cover, to avoid a very subtle misfeature of SSAS.&lt;/p&gt;  &lt;p&gt;When the relationship is materialized, SSAS will resolve it during processing time issuing a more complex query, during the partition processing (not dimension, I have written the right word: &lt;strong&gt;partition&lt;/strong&gt;!) issuing a JOIN between the fact table and the intermediate dimension, to gather the value of the key for the final dimension from the intermediate one. This will lead to poor processing performances, but it is something that we already know. Anyway, what is important to point out is that the relationship is resolved during partition, not dimension processing.&lt;/p&gt;  &lt;p&gt;The real problem comes when we need to update the relationship. We might think (at least this is what I thought) that issuing a ProcessUpdate on the intermediate dimension would refresh the relationship and perform all the necessary updates. This is not true. Since the materialized relationship is resolved during partition processing, any dimension processing will not refresh it. You can try to ProcessUpdate the intermediate or the final dimension: no way, the relationship still uses the data that was there when the partition was processed first time. &lt;strong&gt;If we want to refresh this relationship, the only way is to reprocess the partition&lt;/strong&gt;, at that point we will have the new data correctly available.&lt;/p&gt;  &lt;p&gt;This might be a very big problem if, for very large cubes, we decide to reprocess only the newest partitions, reprocessing only the needed aggregations for the older ones. If older partition will not be processed they will use the older version of the relationship. We will end up with an inconsistent situation where some partitions use a relationship and other use a different one, depending on when they have been last processed.&lt;/p&gt;  &lt;p&gt;Clearly, if we rely on non-materialized relationships, everything will work fine since the relationship will rely only on dimensional data and does not need to be resolved during partition processing. In fact, issuing a ProcessUpdate on the intermediate dimension will imediately refresh the non materialized relationship, as it is supposed to do.&lt;/p&gt;  &lt;p&gt;I think BOL should be much clearer on this, materializing a relationship is not just a matter of query speed, it has subtle consequences that, at their extreme, might lead to incorrect results from the cube.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=SSAS: Reference materialized dimension might produce incorrect results&amp;amp;body=Seen on SQLblog.com: %0A%0A%09SSAS: Reference materialized dimension might produce incorrect results%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/25/ssas-reference-materialized-dimension-might-produce-incorrect-results.aspx" target="_blank" title = "Email SSAS: Reference materialized dimension might produce incorrect results"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/25/ssas-reference-materialized-dimension-might-produce-incorrect-results.aspx&amp;amp;title=SSAS%3a+Reference+materialized+dimension+might+produce+incorrect+results" target="_blank" title = "Submit SSAS: Reference materialized dimension might produce incorrect results to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/25/ssas-reference-materialized-dimension-might-produce-incorrect-results.aspx&amp;amp;phase=2" target="_blank" title = "Submit SSAS: Reference materialized dimension might produce incorrect results to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/25/ssas-reference-materialized-dimension-might-produce-incorrect-results.aspx&amp;amp;title=SSAS%3a+Reference+materialized+dimension+might+produce+incorrect+results" target="_blank" title = "Submit SSAS: Reference materialized dimension might produce incorrect results to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/25/ssas-reference-materialized-dimension-might-produce-incorrect-results.aspx&amp;amp;title=SSAS%3a+Reference+materialized+dimension+might+produce+incorrect+results" target="_blank" title = "Submit SSAS: Reference materialized dimension might produce incorrect results to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/25/ssas-reference-materialized-dimension-might-produce-incorrect-results.aspx&amp;amp;title=SSAS%3a+Reference+materialized+dimension+might+produce+incorrect+results&amp;amp;;top=1" target="_blank" title = "Add SSAS: Reference materialized dimension might produce incorrect results to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=12198" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Dimensional+Model/default.aspx">Dimensional Model</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSAS/default.aspx">SSAS</category></item><item><title>Measure Tool – Making SSAS measures physical to apply security</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/05/measure-tool.aspx</link><pubDate>Thu, 05 Feb 2009 10:18:34 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:11730</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>4</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/11730.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=11730</wfw:commentRss><description>&lt;p&gt;The security model of SSAS prevents us to apply security limitations to calculated members. We can hide &lt;strong&gt;physical&lt;/strong&gt; members but we have no means to hide calculated members to any role. By preventing access to the physical measures, the user will not be able to see the result of the calculated measure, nevertheless he will always see the metadata definition of the member and, if he tries to add it to a query, he will get an error as a result.&lt;/p&gt;  &lt;p&gt;Even if this approach is effective, it leads to a very poor user experience: it would be much better to completely hide the calculated measure to any user who does not have access to it.&lt;/p&gt;  &lt;p&gt;A solution to this situation might be found by fooling SSAS: if we create an empty physical measure and then use MDX code to override its value with our MDX calculation, then we will be able to apply security to the physical measure and still have the ability to define its value using a calculated member.&lt;/p&gt;  &lt;p&gt;An example is much easier to understand that any theoretical explanation: let us suppose that we want to make the Gross Profit calculated measure of Adventure Works a physical one.&lt;/p&gt;  &lt;p&gt;Adapting in some way the technique showed in &lt;a href="http://sqlblog.com/blogs/marco_russo/archive/2007/09/02/datetool-dimension-an-alternative-time-intelligence-implementation.aspx" target="_blank"&gt;this post&lt;/a&gt; by Marco Russo, we might be tempted to create a measure group containing an empty physical measure (GrossProfit), without linking the measure group to any dimension. Sadly to say, SSAS will refuse to deploy a cube that contains a measure group not related to any dimension. So we will need to create a physical measure group linked to at least one dimension in order to make this technique works.&lt;/p&gt;  &lt;p&gt;We can define a new view:&lt;/p&gt;  &lt;div style="border-right:gray 1px solid;padding-right:4px;border-top:gray 1px solid;padding-left:4px;font-size:8pt;padding-bottom:4px;margin:20px 0px 10px;overflow:auto;border-left:gray 1px solid;width:97.5%;cursor:text;max-height:200px;line-height:12pt;padding-top:4px;border-bottom:gray 1px solid;font-family:consolas, 'Courier New', courier, monospace;background-color:#f4f4f4;"&gt;   &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, 'Courier New', courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;VIEW&lt;/span&gt; MeasureTool &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;
     &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 
        GrossProfit = &lt;span style="color:#0000ff;"&gt;CAST&lt;/span&gt; (0 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;REAL&lt;/span&gt;),
        TimeKey
     &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;
        DimTime&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;And then add the view to our DSV and create a measure group based on this view, relating it to the time dimension through the TimeKey. Note that we choose the DimTime just because it is a small dimension, any very small dimension will work as we are not using this relationship in any way, it is only a technicism to make the OLAP cube work.&lt;/p&gt;

&lt;p&gt;If we deploy the cube at this point, the new pjysical measure will always contain zero, which is not what we want. Nevertheless, a very simple MDX SCOPE will solve the problem and perform the magic:&lt;/p&gt;

&lt;div style="border-right:gray 1px solid;padding-right:4px;border-top:gray 1px solid;padding-left:4px;font-size:8pt;padding-bottom:4px;margin:20px 0px 10px;overflow:auto;border-left:gray 1px solid;width:97.5%;cursor:text;max-height:200px;line-height:12pt;padding-top:4px;border-bottom:gray 1px solid;font-family:consolas, 'Courier New', courier, monospace;background-color:#f4f4f4;"&gt;
  &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, 'Courier New', courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#0000ff;"&gt;SCOPE&lt;/span&gt; (Measures.GrossProfit);
    THIS = [Measures].[Sales Amount] - [Measures].[Total Product Cost];
&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;SCOPE&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now the GrossProfit measure will perform the correct computation but it will be a physical measure, so we can apply security on it and hide it to all the users that are not allowed to see it.&lt;/p&gt;

&lt;p&gt;The physical space of the cube is grown but, using a small dimension, the growth will be negligible.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Measure Tool – Making SSAS measures physical to apply security&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Measure Tool – Making SSAS measures physical to apply security%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/05/measure-tool.aspx" target="_blank" title = "Email Measure Tool – Making SSAS measures physical to apply security"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/05/measure-tool.aspx&amp;amp;title=Measure+Tool+%e2%80%93+Making+SSAS+measures+physical+to+apply+security" target="_blank" title = "Submit Measure Tool – Making SSAS measures physical to apply security to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/05/measure-tool.aspx&amp;amp;phase=2" target="_blank" title = "Submit Measure Tool – Making SSAS measures physical to apply security to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/05/measure-tool.aspx&amp;amp;title=Measure+Tool+%e2%80%93+Making+SSAS+measures+physical+to+apply+security" target="_blank" title = "Submit Measure Tool – Making SSAS measures physical to apply security to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/05/measure-tool.aspx&amp;amp;title=Measure+Tool+%e2%80%93+Making+SSAS+measures+physical+to+apply+security" target="_blank" title = "Submit Measure Tool – Making SSAS measures physical to apply security to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2009/02/05/measure-tool.aspx&amp;amp;title=Measure+Tool+%e2%80%93+Making+SSAS+measures+physical+to+apply+security&amp;amp;;top=1" target="_blank" title = "Add Measure Tool – Making SSAS measures physical to apply security to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=11730" width="1" height="1"&gt;</description></item><item><title>SQLBI: Yet Another DWH Methodology?</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx</link><pubDate>Fri, 26 Sep 2008 21:21:56 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:9113</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/9113.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=9113</wfw:commentRss><description>&lt;p&gt;It is several years now that I and &lt;a href="http://sqlblog.com/blogs/marco_russo/default.aspx" target="_blank"&gt;Marco Russo&lt;/a&gt; enjoy ourself developing BI solutions and teaching our customers how to build them. We started with Kimball methodology, then we tried Inmon's one and finally a mix of both, tailored to ours and our customer needs. We tested the method on some projects and, at the end, we came up with a complete methodology that we now adopt as &amp;quot;our&amp;quot; standard. &lt;/p&gt;  &lt;p&gt;When we felt confident that our methodology was mature enough to get described, we decided to write the &lt;a href="http://www.sqlbi.com/sqlbimethodology.aspx" target="_blank"&gt;first whitepaper&lt;/a&gt;, in which we introduce it. The goal of the publication on the web is that of discussing it with everybody interested in the development of BI solution.&lt;/p&gt;  &lt;p&gt;In the paper we do not spend too much time on theoretical discussion about what a fact or a dimension is, our focus is where our customers are: &amp;quot;on the market&amp;quot;. We do not talk about generic tools: we use Microsoft suite for BI and our efforts are in the direction of taking the best out of Microsoft tools.&lt;/p&gt;  &lt;p&gt;We decided to share our experience with other BI experts by publishing the paper, we'd like to get comments and feedbacks on it. If you want to drop a line with your thoughts about it, feel free to do it in the &lt;a href="http://www.sqlbi.eu/Forum/tabid/72/forumid/20/scope/threads/language/it-IT/Default.aspx"&gt;SQLBI Methodology forum&lt;/a&gt;.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=SQLBI: Yet Another DWH Methodology?&amp;amp;body=Seen on SQLblog.com: %0A%0A%09SQLBI: Yet Another DWH Methodology?%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx" target="_blank" title = "Email SQLBI: Yet Another DWH Methodology?"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx&amp;amp;title=SQLBI%3a+Yet+Another+DWH+Methodology%3f" target="_blank" title = "Submit SQLBI: Yet Another DWH Methodology? to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx&amp;amp;phase=2" target="_blank" title = "Submit SQLBI: Yet Another DWH Methodology? to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx&amp;amp;title=SQLBI%3a+Yet+Another+DWH+Methodology%3f" target="_blank" title = "Submit SQLBI: Yet Another DWH Methodology? to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx&amp;amp;title=SQLBI%3a+Yet+Another+DWH+Methodology%3f" target="_blank" title = "Submit SQLBI: Yet Another DWH Methodology? to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx&amp;amp;title=SQLBI%3a+Yet+Another+DWH+Methodology%3f&amp;amp;;top=1" target="_blank" title = "Add SQLBI: Yet Another DWH Methodology? to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=9113" width="1" height="1"&gt;</description></item><item><title>SSIS: living in a parallel world? Not yet...</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx</link><pubDate>Sun, 14 Sep 2008 19:57:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8899</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>2</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/8899.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=8899</wfw:commentRss><description>&lt;P&gt;Today I come into a nice bug (misfeature?) of SSIS 2008 and I'd like to share it with you. Let's start from the beginning:&lt;/P&gt;
&lt;P&gt;One of the keys to make something speedy is to parallelize it. In TableDifference I read from two inputs, compare them and produce several outputs for new, deleted, updated rows and so on. It is the classical "produce/consumer" paradigm that works fine in parallel, creating a consumer thread that compares rows and different threads to produce them. &lt;/P&gt;
&lt;P&gt;During the porting of the component in SQL 2008 I discovered that my code does not work as expected. It reads all the lines, then terminates abnormally without producing a single row of output. It took me a couple of hours and several coffes to discover the change in the way SSIS handles asyncronous components causing my bug.&lt;/P&gt;
&lt;P&gt;In order to make the problem easier to understand (for microsoft connect too), I produced the same behaviour with a much simpler script component. Imagine to have a script transformation that needs to make some very complex work on each row. You will end up with something like this:&lt;/P&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Input0_ProcessInputRow(Input0Buffer Row) {
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction(Row);
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (Row.EndOfRowset ()) {
           OutputBuffer.SetEndOfRowset ();
        }
    }&lt;/PRE&gt;
&lt;P&gt;But, if you have a 64 CPU computer. You can imagine to detach many threads, each one handling just one very complex function, in this way you will produce a massive parallel computation. Wow! The solution to get maximum speed would be this:&lt;/P&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Input0_ProcessInputRow(Input0Buffer Row) {
        Thread T = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Thread(SendAsyncRow);
        T.Start(Row.EndOfRowset());
    }

    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SendAsyncRow(Object O) {
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction();
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; ((&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt;)O == &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;) {
            Output0Buffer.SetEndOfRowset();
        }
    }&lt;/PRE&gt;
&lt;P&gt;You detach a separate thread for each row, the thread will compute the very complex function and send it to the output buffer as soon as it is ready. In order to make SSIS understand when everything is finished, you signal SetEndOfRowset in the last thread.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;Don't start crying, this code will never work, the SetEndOfRowset is called on the last read line and not on the last produced one, but this is just pseudocode to understand the topic, don't blame me for inconsistencies. :) Let's go on with the main topic.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Under SSIS 2005 this code (in VB, of course) would work fine as the engine detects the end of processing when it receives the EndOfRowset on the outputs. In SSIS 2008 the engine detects the end of the processing as soon as the &lt;EM&gt;&lt;STRONG&gt;last call to ProcessInputRow has finished&lt;/STRONG&gt;&lt;/EM&gt;. So, in our case, after the last thread has been detached SSIS believes that the processing is finished and calls the cleaning up of the component, completely ignoring both the presence of separate threads running and our williness to not terminate the component because we know that we need some more time.&lt;/P&gt;
&lt;P&gt;The result? As with any other parallel bug you will sometime get a crash, on the same inputs sometime finish corectly, sometime get an error... the nightmare of any programmer.&lt;/P&gt;
&lt;P&gt;If you want to try it by yourself, cut and paste this code to a transformation script in a data flow that process some lines ( rows 10/20 lines are enough):&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.Data;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.SqlServer.Dts.Pipeline.Wrapper;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.SqlServer.Dts.Runtime.Wrapper;

&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Threading;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; ScriptMain : UserComponent {

    &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; useThreads = &lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;;

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Processes input rows&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;param name="Row"&amp;gt;&amp;lt;/param&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Input0_ProcessInputRow(Input0Buffer Row) {
        Thread T = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Thread(SendAsyncRow);

        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (useThreads) {
            T.Start(Row.EndOfRowset());
        } &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt; {
            SendRow();
        }
    }

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Sends a row in sync mode&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SendRow() {
        &lt;SPAN class=rem&gt;// Thread.Sleep(100);&lt;/SPAN&gt;
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction();
    }

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Sends a row in async mode&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;param name="O"&amp;gt;&amp;lt;/param&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SendAsyncRow(Object O) {
        Thread.Sleep(100);
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction();
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; ((&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt;)O == &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;) {
            Output0Buffer.SetEndOfRowset();
        }
    }

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Not very complex... but it's a demo!&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; VeryComplexFunction() {
        &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; 10;
    }
}&lt;/PRE&gt;
&lt;P&gt;using Serial mode (useThreads se to false) everything works fine. Using parallel mode (useThreads set to true) SSIS will crash and produce no output at all. The bug in TableDifference was very similar to that, I needed to handle the wait for termination of the consumer process during the ProcessInput function.&lt;/P&gt;
&lt;P&gt;It is not the first time I discover inconsistencies in the way SSIS handles parallelism, in order to try to make it easier to write code (using 2008 mode there is no need to call SetEndOfRowset and your program will run fine if you forget it) the architects of SSIS introduce a behavior that will make better and correct code crash. If you believe this is a problem, vote &lt;A href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=367692" target=_blank&gt;here&lt;/A&gt;, anyway... be aware of it, it mighe be useful in the future. :)&lt;/P&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=SSIS: living in a parallel world? Not yet...&amp;amp;body=Seen on SQLblog.com: %0A%0A%09SSIS: living in a parallel world? Not yet...%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx" target="_blank" title = "Email SSIS: living in a parallel world? Not yet..."&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx&amp;amp;title=SSIS%3a+living+in+a+parallel+world%3f+Not+yet..." target="_blank" title = "Submit SSIS: living in a parallel world? Not yet... to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx&amp;amp;phase=2" target="_blank" title = "Submit SSIS: living in a parallel world? Not yet... to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx&amp;amp;title=SSIS%3a+living+in+a+parallel+world%3f+Not+yet..." target="_blank" title = "Submit SSIS: living in a parallel world? Not yet... to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx&amp;amp;title=SSIS%3a+living+in+a+parallel+world%3f+Not+yet..." target="_blank" title = "Submit SSIS: living in a parallel world? Not yet... to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx&amp;amp;title=SSIS%3a+living+in+a+parallel+world%3f+Not+yet...&amp;amp;;top=1" target="_blank" title = "Add SSIS: living in a parallel world? Not yet... to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8899" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/TableDifference/default.aspx">TableDifference</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSIS/default.aspx">SSIS</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Components/default.aspx">Components</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx">SQL</category></item><item><title>Reading zip files with SSIS</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx</link><pubDate>Wed, 16 Jul 2008 16:25:53 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7868</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>7</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/7868.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=7868</wfw:commentRss><description>&lt;p&gt;Playing with SSIS I normally have to read flat files that come in zip format. The standard procedure here is to launch winzip, decompress the file, read it with a flat file adapter and then delete the uncompressed file. This behaviour generates a lot of useless I/O on temporary disks to decompress a file that will be soon deleted.&lt;/p&gt; &lt;p&gt;Another way of solving the problem is to have a look at &lt;a href="http://www.codeplex.com/DotNetZip/" target="_blank"&gt;DotNetZip library&lt;/a&gt;. A very smart programmer wrote a library that makes opening zip files very easy using .NET. He also added in version 1.6 a great function: OpenReader. You can open a zip file, look into its entries and open a stream reader on it.&lt;/p&gt; &lt;p&gt;Using this tecnique you can open a stream reader directly into the zip file and the process the stream using a VB source component in your data flow package.&lt;/p&gt; &lt;p&gt;And... Yes, you cannot use the flat file adapter. You will need to parse the stream and read strings from it but you will end up with very few I/O when compared to the unzip / read / delete solution. As I/Os are very expensive, this tecnique may speed up your package significantly.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Reading zip files with SSIS&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Reading zip files with SSIS%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx" target="_blank" title = "Email Reading zip files with SSIS"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx&amp;amp;title=Reading+zip+files+with+SSIS" target="_blank" title = "Submit Reading zip files with SSIS to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx&amp;amp;phase=2" target="_blank" title = "Submit Reading zip files with SSIS to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx&amp;amp;title=Reading+zip+files+with+SSIS" target="_blank" title = "Submit Reading zip files with SSIS to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx&amp;amp;title=Reading+zip+files+with+SSIS" target="_blank" title = "Submit Reading zip files with SSIS to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx&amp;amp;title=Reading+zip+files+with+SSIS&amp;amp;;top=1" target="_blank" title = "Add Reading zip files with SSIS to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7868" width="1" height="1"&gt;</description></item><item><title>TableDifference version 2.0 has been released</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx</link><pubDate>Fri, 22 Feb 2008 12:45:07 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:5202</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>3</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/5202.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=5202</wfw:commentRss><description>&lt;p&gt;Table difference is an SSIS custom component designed to simplify the management of slowly changing dimensions and – in general – to check the differences between two tables or data flow with SSIS.&lt;/p&gt; &lt;p&gt;Its main advantage over Microsoft standard SCD component is its speed and ease of use, the component receives input from two sorted sources and generates different outputs for unchanged, new, deleted or updated rows. &lt;p&gt;The project is freeware, full source code is available at &lt;a href="http://www.sqlbi.com"&gt;www.sqlbi.com&lt;/a&gt;. &lt;h2&gt;Note to version 1.x users&lt;/h2&gt; &lt;p&gt;The internal structure of the metadata of TableDifference is very different from the previous one. The component is able to read metadata from the previous version and write them with the new format as soon as it is called from inside BIDS so you will be able to reload all the previous metadata without loss of functionality. &lt;p&gt;However, in writing the new metadata, the component changes the lineage IDs of all the output columns so, when you open a package that contains a previous version of TableDifference, you will need to open its designer to check that everything worked fine and the correct the subsequent flows by double clicking on the components that use TableDifference outputs. I have converted a lot of packages without any problems but, if you encounter something strange, do not hesitate to contact me. &lt;h2&gt;Introduction&lt;/h2&gt; &lt;p&gt;One question that arises very often in Data Warehouse programming is “what are the differences between these two tables/flows of data?” It is often the case in SCD management; you receive several millions of customers and should decide what changes need to be done after your last successful load. &lt;p&gt;Using SSIS we have the SCD component, it works but it does it slow that in the production environment it is quite always convenient to create an “ad hoc” solution to handle the SCD. &lt;p&gt;We decided to write an SSIS component that has two inputs, one for the “old” and one for the “new” data, compares all the rows that come in from the old and the new flow and sends them to different outputs, namely: &lt;ul&gt; &lt;li&gt;Unchanged rows (are the same in both input)&lt;/li&gt; &lt;li&gt;Deleted rows (appear in old but not in new)&lt;/li&gt; &lt;li&gt;New rows (appear in new but not in old)&lt;/li&gt; &lt;li&gt;Updated rows (appear in both flows but something is changed)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The following picture illustrates the component functionality better than thousand words. &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image002_2.jpg"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="240" alt="clip_image002" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image002_thumb.jpg" width="464" border="0"&gt;&lt;/a&gt; &lt;p&gt;As not every update is to be handled the same way, it is possible to tag each column with an integer; the number of updated outputs is determined by the number of tags, one for each, in this way you can tag with “10” the historical attributes, with “20” other columns and decide what kind of operation to carry on with the different updates. &lt;p&gt;The inputs MUST be sorted and have a collection of fields (keys) that let the component decide when two rows from the inputs represent the same row, but this is easily accomplished by SQL Server with a simple “order by” and a convenient index; moreover the SCD do normally maintain an index by the business key, so the sorting requirement is easily accomplished and do not represent a problem. &lt;h2&gt;The main structure&lt;/h2&gt; &lt;p&gt;The structure of the component is pretty simple: &lt;ul&gt; &lt;li&gt;Old Flow Input: it should be attached to a convenient query that returns all the current rows from the SCD&lt;/li&gt; &lt;li&gt;New Flow Input: it can be connected to the flow where the new structure of the SCD has been computed.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Each input has a buffer where all the incoming rows are directed and maintained. &lt;p&gt;A separate thread starts as soon as data from both buffers is available and checks for the differences between them, sending the rows to the appropriate output and then removing the buffered rows from the buffers. &lt;p&gt;The buffer does not need to maintain all the data from the SCD, data is removed as soon as it can be compared with a corresponding row: the buffer, even for a several million record table, should be pretty small (but read the document to the end… some tricks may be useful to avoid memory consumption). &lt;h3&gt;The outputs&lt;/h3&gt; &lt;p&gt;The component has three standard outputs for new, deleted and unchanged rows. The number of updated rows output is determined by the user via the component editor, one output is provided for each different updateID that is inserted by the user. The outputs are named “UpdateID” followed by the updateID defined by the user.  &lt;p&gt;Of course, you can easily change the name of the output to something more interesting like “Updated historical attribute” and we encourage you to do so! &lt;p&gt;The collection of output fields is computed by the component via the intersection of the two inputs: if one column appears in only one input it is not managed, if it appears in both then it will be compared and outputted. &lt;h3&gt;Installing TableDifference&lt;/h3&gt; &lt;p&gt;Installation is very simple: &lt;p&gt;· copy TableDifference.DLL into  &lt;p&gt;“&amp;lt;Program Files&amp;gt;\Microsoft SQL Server\90\DTS\PipelineComponents” &lt;p&gt;· add the DLL to the GAC using “GACUTIL –I TableDifference.DLL” &lt;p&gt;No installer for the moment… sorry. &lt;p&gt;Note for Vista users: you need to run these command on a command line opened with administrator privileges to perform the tasks. &lt;h2&gt;Using TableDifference&lt;/h2&gt; &lt;p&gt;After the component is installed you should add it to the toolbar as for every SSIS component and then you are ready to use it. &lt;p&gt;After both inputs has been attached, by double clicking on the component, you reach the component editor that shows a single window like this: &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image004_2.jpg"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="360" alt="clip_image004" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image004_thumb.jpg" width="311" border="0"&gt;&lt;/a&gt; &lt;p&gt;A few words about what is happening just before the component editor pops up: &lt;ol&gt; &lt;li&gt;TableDifference analyzes all the columns in both inputs and compares their names. If the name of two columns and their corresponding types are identical, TableDifference adds them to the available columns to manage.&lt;/li&gt; &lt;li&gt;If the flows are sorted, their sort columns will be marked as key fields, using the same order in which they appear in the sort.&lt;/li&gt; &lt;li&gt;All other columns are assigned a standard Update ID of 10 and are managed as comparable columns.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Using the component editor you need to provide these information for the columns: &lt;ul&gt; &lt;li&gt;&lt;b&gt;Check Option&lt;/b&gt;: you can choose the column type between:&lt;/li&gt; &lt;ul&gt; &lt;li&gt;&lt;b&gt;Key field&lt;/b&gt;: these column will be used to detect when two rows from the inputs represent the same row. Beware that the inputs must be sorted by those columns&lt;/li&gt; &lt;li&gt;&lt;b&gt;Compare&lt;/b&gt;: these columns will be compared one by one to detect differences&lt;/li&gt; &lt;li&gt;&lt;b&gt;Prefer NEW&lt;/b&gt;: these columns will be copied from the NEW input directly into the output, no check&lt;/li&gt; &lt;li&gt;&lt;b&gt;Prefer OLD&lt;/b&gt;: these columns will be copied from the OLD input directly into the output, no check&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;&lt;b&gt;KeyOrder&lt;/b&gt;: If a column is of type “Key Field” it is the order under which the field appear under the “order by” clause of your query. Beware that the component do not check for the correct sorting sequence, it is up to you to provide this information.&lt;/li&gt; &lt;li&gt;&lt;b&gt;Update ID&lt;/b&gt;: each different UpdateID creates a different output flow. If you need to detect when a change appears in some column you can use different update ID. Beware that the lowest update ID wins, i.e. if AccountNumber has update id of 10 and AddressLine1 has update id of 20, then Accountnumber will be checked first and if a change is detected, the row will go to update output 10, no matter if AddressLine has a difference.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Clicking “OK” is enough for the component to generate the outputs and to define the metadata for all the outputs. &lt;p&gt;In version 2.0 there are a three new panels: &lt;h3&gt;Outputs panel&lt;/h3&gt; &lt;p&gt;In this panel you can choose which output to enable. If you are not interested, for example, in the unchanged output, then you can deselect it from this panel to avoid warnings for unused columns. &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image006_2.jpg"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="357" alt="clip_image006" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image006_thumb.jpg" width="308" border="0"&gt;&lt;/a&gt; &lt;p&gt;You can also rename outputs and provide a concise description of them. Renaming is very useful as it gives the data flow clearness. &lt;h3&gt;Output Details&lt;/h3&gt; &lt;p&gt;This panel let you select the columns for each output. You cannot add any column but you can disable columns for outputs that do not use them. &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image008_2.jpg"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="366" alt="clip_image008" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image008_thumb.jpg" width="316" border="0"&gt;&lt;/a&gt; &lt;p&gt;The upper combo box let you choose an output, in the grid you can select or unselect any column. This feature is useful as it avoids warnings for unused columns. In the picture, the deleted output will receive only the customer key as it will make no use of any other information. &lt;p&gt;Always remember that removing useless output columns increases the performances of the component. &lt;h3&gt;Misc Options&lt;/h3&gt; &lt;p&gt;Under this pane there are miscellaneous options. &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image010_2.jpg"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="392" alt="clip_image010" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/TableDifferenceversion2.0hasbeenreleased_C00B/clip_image010_thumb.jpg" width="338" border="0"&gt;&lt;/a&gt; &lt;p&gt;Here you can define, for string comparisons: &lt;ol&gt; &lt;li&gt;The culture ID to use to perform the comparison. If not specified TableDifference will use the culture ID of the running task. The default is “empty”.&lt;/li&gt; &lt;li&gt;If you want it to ignore casing during string comparisons. The default is unchecked so TableDifference will perform comparison considering case.&lt;/li&gt;&lt;/ol&gt; &lt;h3&gt;Warnings&lt;/h3&gt; &lt;p&gt;This panel will list any unused column from the input. As you might recall, if two columns are not identical regarding name and type, TableDifference will ignore them. This might be an error but the decision is up to you. By checking the warnings panel you can see if TableDifference is working with all the columns you need it to compare.  &lt;h2&gt;FlowSync&lt;/h2&gt; &lt;p&gt;The component works fine and do not consume memory if and only if the input from both flows come in at a synchronized speed: if one input is much faster than the other then the component will start buffering data and consume memory that will be freed only when the buffer starts to shrink. &lt;p&gt;Using the component to compare two tables with 5 millions of records we had several problems with memory, because data came in from one buffer much faster than the other and, after the difference (and hence the buffer on one input) reached 1.5 millions of records, the whole memory of the DtExec process (in a 32 bit virtual space) was filled in. &lt;p&gt;As both inputs were from a simple “Select * From” and the speed from both lines was the same, we discovered that – for some obscure reason – SSIS prefers one input to the other and do not leave enough time to both tasks, resulting in memory consumption by the component. &lt;p&gt;FlowSync is a component that will make two or more flows of data in an SSIS data flow package run at the same speed, by stopping one flow if the others run too slow. It has been created as a convenient companion to TableDifference to resolve the problems with memory occupation, it can be used by its own in the case where you want flows to run at the same speed. &lt;p&gt;It makes use of semaphores to handle synchronization, so no CPU is ever wasted, when the faster flows is stopped all the CPU is free for others (more useful) processes. &lt;p&gt;You can find source code, executable and description of FlowSync at &lt;a href="http://www.sqlbi.com"&gt;www.sqlbi.com&lt;/a&gt;. We normally use flowsync when we need to compare more than half a million rows while we use TableDifference without flow sync for all the smaller tables in a project. 
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=TableDifference version 2.0 has been released&amp;amp;body=Seen on SQLblog.com: %0A%0A%09TableDifference version 2.0 has been released%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx" target="_blank" title = "Email TableDifference version 2.0 has been released"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx&amp;amp;title=TableDifference+version+2.0+has+been+released" target="_blank" title = "Submit TableDifference version 2.0 has been released to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx&amp;amp;phase=2" target="_blank" title = "Submit TableDifference version 2.0 has been released to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx&amp;amp;title=TableDifference+version+2.0+has+been+released" target="_blank" title = "Submit TableDifference version 2.0 has been released to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx&amp;amp;title=TableDifference+version+2.0+has+been+released" target="_blank" title = "Submit TableDifference version 2.0 has been released to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx&amp;amp;title=TableDifference+version+2.0+has+been+released&amp;amp;;top=1" target="_blank" title = "Add TableDifference version 2.0 has been released to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=5202" width="1" height="1"&gt;</description></item><item><title>Table Difference 2.0 - Call for beta</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx</link><pubDate>Mon, 17 Dec 2007 11:53:37 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:4030</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>1</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/4030.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=4030</wfw:commentRss><description>&lt;p&gt;The new version 2.0 of SSIS SCD handling component &lt;a href="http://www.sqlbi.eu/Projects/TableDifference.aspx" target="_blank"&gt;TableDifference&lt;/a&gt; is in beta, I am searching for beta testers and some help in writing an installer for it. You will find all the informations at &lt;a href="http://www.sqlbi.eu"&gt;www.sqlbi.eu&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;The final release of the component will be as usually freely available with sources as soon as it has been tested enough.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Table Difference 2.0 - Call for beta&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Table Difference 2.0 - Call for beta%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx" target="_blank" title = "Email Table Difference 2.0 - Call for beta"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx&amp;amp;title=Table+Difference+2.0+-+Call+for+beta" target="_blank" title = "Submit Table Difference 2.0 - Call for beta to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx&amp;amp;phase=2" target="_blank" title = "Submit Table Difference 2.0 - Call for beta to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx&amp;amp;title=Table+Difference+2.0+-+Call+for+beta" target="_blank" title = "Submit Table Difference 2.0 - Call for beta to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx&amp;amp;title=Table+Difference+2.0+-+Call+for+beta" target="_blank" title = "Submit Table Difference 2.0 - Call for beta to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx&amp;amp;title=Table+Difference+2.0+-+Call+for+beta&amp;amp;;top=1" target="_blank" title = "Add Table Difference 2.0 - Call for beta to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=4030" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/TableDifference/default.aspx">TableDifference</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSIS/default.aspx">SSIS</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Components/default.aspx">Components</category></item><item><title>SSIS Multicast and Trash or Separate and Union?</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx</link><pubDate>Thu, 15 Nov 2007 12:15:22 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:3345</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>2</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/3345.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=3345</wfw:commentRss><description>&lt;p&gt;Today I was&amp;nbsp;optimizing&amp;nbsp;a package that handles a very common topic: process some rows and send all them to a flow but, for some of them, make additional processing. &lt;/p&gt; &lt;p&gt;A simple Multicast and a Conditional Split solve the problem, the picture explains it better than my words:&lt;/p&gt; &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/SSISandtheageofconsumerism_C3D4/p.png"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="358" alt="" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/SSISandtheageofconsumerism_C3D4/p_thumb.png" width="461" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Now, I was wondering why we should duplicate one million rows to two millions and then trash half of them away. I thought a better solution was to separate the rows before and duplicate only half a million, bringing them together again with the other half million from the other flow. So I tried this solution, thas does exactly the same but does not trash anything. We are not in the age of consumerism and we do not like to trash anything, don't we?&lt;/p&gt; &lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/SSISandtheageofconsumerism_C3D4/image_3.png"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="348" alt="image" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/SSISandtheageofconsumerism_C3D4/image_thumb_3.png" width="369" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Well, even if I thought it would be a better solution, it is not. The first one (with one million rows of 1K each) takes approximately 13 seconds to run, the second one with the same data 16 seconds, that is 23% slower than before.&lt;/p&gt; &lt;p&gt;So, the conclusion is that SSIS still lives in the age of consumerism, the process of UNION ALL takes a very long time to process and makes trashing a better solution. There are good explanations for this (UNION ALL does a lot more work than Multicast does) but I did not think that a 23% degradation would occur. &lt;/p&gt; &lt;p&gt;The lesson is: it is best to trash then try to recycle, at least with data with SSIS. :)&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=SSIS Multicast and Trash or Separate and Union?&amp;amp;body=Seen on SQLblog.com: %0A%0A%09SSIS Multicast and Trash or Separate and Union?%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx" target="_blank" title = "Email SSIS Multicast and Trash or Separate and Union?"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx&amp;amp;title=SSIS+Multicast+and+Trash+or+Separate+and+Union%3f" target="_blank" title = "Submit SSIS Multicast and Trash or Separate and Union? to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx&amp;amp;phase=2" target="_blank" title = "Submit SSIS Multicast and Trash or Separate and Union? to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx&amp;amp;title=SSIS+Multicast+and+Trash+or+Separate+and+Union%3f" target="_blank" title = "Submit SSIS Multicast and Trash or Separate and Union? to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx&amp;amp;title=SSIS+Multicast+and+Trash+or+Separate+and+Union%3f" target="_blank" title = "Submit SSIS Multicast and Trash or Separate and Union? to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx&amp;amp;title=SSIS+Multicast+and+Trash+or+Separate+and+Union%3f&amp;amp;;top=1" target="_blank" title = "Add SSIS Multicast and Trash or Separate and Union? to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=3345" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSIS/default.aspx">SSIS</category></item><item><title>Visio and SQL Extended Properties: a tool to marry them</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx</link><pubDate>Wed, 07 Nov 2007 10:00:32 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:3233</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>2</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/3233.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=3233</wfw:commentRss><description>&lt;p&gt;Visio database models have column descriptions, SQL Server has extended properties where to store them but, even if they share the same producer, it seems that Visio is unable to store column descriptions in extended properties so that other tools can gather the same information easily and produce a decent documentation of a database.&lt;/p&gt; &lt;p&gt;After some browsing on the web, I was unable to find a tool that let&amp;nbsp;Visio save the table and column descriptions in SQL Server, so I decided it was time to code it by myself.&lt;/p&gt; &lt;p&gt;First&amp;nbsp;you need to generate the DDL script of the database having DDL Script commens ON for all the columns (which can be configured in the driver options) as in the following picture:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/VisioandExtendedPropertiesatooltomarryth_D6C3/Tp_1.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="394" alt="Tp" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/VisioandExtendedPropertiesatooltomarryth_D6C3/Tp_thumb_1.png" width="354" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;In the DDL file, VISIO adds header of comments to each table like this:&lt;/p&gt; &lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;/* Create new table "Sales.Dim_Customers".                                         */
/* "Sales.Dim_Customers" : Contains all the customer with various attributes used  */
/* to analyze them. Does not contain (bla bla bla)                                 */
/* "ID_Customer" : Primary key of the table                                        */
/* "CustomerCode" : Customer code as seen in the OLTP database                     */
/* "ID_Geography" : Key in Dim_Geography. It is not shown to the end user          */
/* "MaritalStatus" : Description of the marital status (Single / Married)          */
/* "Gender" : Description of the gender (Male, Female)                             */
&lt;/span&gt;&lt;span style="color:#808080;"&gt;...&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;...&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;...
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;create&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;table&lt;/span&gt;&lt;span style="color:#000000;"&gt; "Sales.Dim_Customers" &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
"ID_Customer" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;identity&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"CustomerCode" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;nvarchar&lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;15&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"ID_Geography" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"MaritalStatus" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;nvarchar&lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;20&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"Gender" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;nvarchar&lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;20&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null)&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;I have written a simple parser (&lt;strong&gt;GenerateExtendedAttrib&lt;/strong&gt;) that looks for comments in this form in a DDL file (starting with "Create new table", then checks for column names and so on)&amp;nbsp;and will finally generate the sp_addextendedproperty calls to define all the column and table descriptions. &lt;/p&gt;
&lt;p&gt;The code fragment above generates this:&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;EXEC&lt;/span&gt;&lt;span style="color:#000000;"&gt; sys.sp_addextendedproperty 
    @name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'MS_Description'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @value&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Contains all the customer with various attributes used to analyze...'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level0type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'SCHEMA'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level0name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Sales'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level1type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'TABLE'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level1name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Dim_Customers'&lt;/span&gt;&lt;span style="color:#808080;"&gt;;
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;EXEC&lt;/span&gt;&lt;span style="color:#000000;"&gt; sys.sp_addextendedproperty 
    @name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'MS_Description'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @value&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Primary key of the table'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level0type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'SCHEMA'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level0name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Sales'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level1type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'TABLE'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level1name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Dim_Customers'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level2type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'COLUMN'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level2name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'ID_Customer'&lt;/span&gt;&lt;span style="color:#808080;"&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;You can call the utility with "/Append" in order to have the property definitions appended to the original file (which, in turn, can be run to have the database created) or you can call it without parameters, in this case the code is written to the console and you can redirect it wherever you want.&lt;/p&gt;
&lt;p&gt;The tool can be downloaded at &lt;a href="http://www.sqlbi.eu"&gt;www.sqlbi.eu&lt;/a&gt;&amp;nbsp;and is provided with sources (it is indeed a very simple yet effective gadget) so you can adapt it to whatever your needs are.&lt;/p&gt;
&lt;p&gt;Have fun and, if you make any change to the code that might be useful, send me a note so I can update the public release.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Visio and SQL Extended Properties: a tool to marry them&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Visio and SQL Extended Properties: a tool to marry them%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx" target="_blank" title = "Email Visio and SQL Extended Properties: a tool to marry them"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx&amp;amp;title=Visio+and+SQL+Extended+Properties%3a+a+tool+to+marry+them" target="_blank" title = "Submit Visio and SQL Extended Properties: a tool to marry them to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx&amp;amp;phase=2" target="_blank" title = "Submit Visio and SQL Extended Properties: a tool to marry them to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx&amp;amp;title=Visio+and+SQL+Extended+Properties%3a+a+tool+to+marry+them" target="_blank" title = "Submit Visio and SQL Extended Properties: a tool to marry them to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx&amp;amp;title=Visio+and+SQL+Extended+Properties%3a+a+tool+to+marry+them" target="_blank" title = "Submit Visio and SQL Extended Properties: a tool to marry them to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx&amp;amp;title=Visio+and+SQL+Extended+Properties%3a+a+tool+to+marry+them&amp;amp;;top=1" target="_blank" title = "Add Visio and SQL Extended Properties: a tool to marry them to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=3233" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx">SQL</category></item><item><title>SQL: Merge two &amp;quot;history tracking&amp;quot; tables</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx</link><pubDate>Mon, 15 Oct 2007 18:36:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:2989</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>8</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/2989.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=2989</wfw:commentRss><description>&lt;p&gt;If you&amp;nbsp;have two columns in a table that "remember" their old values in two different historical tables, as it is the case in AdventureWorks with EmployeePayHistory and EmployeeDepartmentHistory, you may need (or just wonder how) to merge these two tables into only one historical table that will keep track of both columns. &lt;/p&gt; &lt;p&gt;This&amp;nbsp;has been my "problem of the day" and, after some thoughts, I came up with a pattern of solution that I'd like to share with you both to see if you have a better solution and to have the code at hand when I'll need later. :)&lt;/p&gt; &lt;p&gt;Before using the real table, I made up a simple test case with a Product table with only two fields a couple of variation tables (VariationA and VariationB):&lt;/p&gt; &lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  Sample table Products, only two columns A and B. The current value of the row is (D, 4)
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt;&lt;span style="color:#000000;"&gt; Products &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    A &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CHAR&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;1&lt;/span&gt;&lt;span style="color:#808080;"&gt;),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    B &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT
&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt;&lt;span style="color:#000000;"&gt; products &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;A&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; B&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'D'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 4&lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  Variations for column A
--
--      ------------------
--      Year    Old Value
--      ------------------
--      2001        A
--      2002        B
--      2003        C
--      2005        D
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;   
    Position &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValue &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VARCHAR&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;5&lt;/span&gt;&lt;span style="color:#808080;"&gt;),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DATETIME&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;1&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'A'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2001'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;2&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'B'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2002'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;3&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'C'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2003'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;4&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'D'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2005'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  Variations for column B
--
--      ------------------
--      Year    Old Value
--      ------------------
--      2000        1
--      2003        2
--      2004        3
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;   
    Position &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValue &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DATETIME&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;1&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2000'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;2&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 2&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2003'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;3&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 3&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2004'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The query that mixes all these variations into a single table is pretty easy but it took me some time to discover.&amp;nbsp;My solution is to detect what was the value of "B" when a variation in "A" happened and vice versa. As the values stored are "old" values, we know that the value of&amp;nbsp;A at a certain date is the value&amp;nbsp;stored in the first variation for&amp;nbsp;A AFTER that date. The only special case is the current time: if no variation record is found then we know that the value to use is the current value of the record in the product table. The same is obviously true for B.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I ended up with this&amp;nbsp;pattern query:&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  AllEvents contains all the events from both VariationA and VariationB,
--  and will detect, for each variation that happened, what was
--  the value of the other column at that time, building in this way the
--  merged variation list.
--  The final SELECT will return the sorted and DISTINCTed result. 
--  Then final COALESCE is needed because if a value is NULL it 
--  means that it should contain the "current" value of the column
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt;&lt;span style="color:#000000;"&gt; AllEvents &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
        OldValueOfA  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfA&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#008000;"&gt;-- Old value of A
&lt;/span&gt;&lt;span style="color:#000000;"&gt;        OldValueOfB  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfB&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#008000;"&gt;-- Old value of B
&lt;/span&gt;&lt;span style="color:#000000;"&gt;        ChangeDate   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate      &lt;/span&gt;&lt;span style="color:#008000;"&gt;-- Date of change
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfA &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfB &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 OldValue 
                                 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB V
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA 
        &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;UNION ALL&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfA &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 OldValue 
                                 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA V
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfB &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB
        &lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events
    &lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DISTINCT
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfA  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfA&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; A &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; Products&lt;/span&gt;&lt;span style="color:#808080;"&gt;)),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfB  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfB&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; B &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; Products&lt;/span&gt;&lt;span style="color:#808080;"&gt;))
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    AllEvents
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;By&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Clearly, i could have written some VB code in SSIS to solve the same problem. Nevertheless, having a pattern query at hand is useful because the pattern can be easily adapted to any real world situation with only&amp;nbsp;SQL Management Studio&amp;nbsp;at hand. The following code is the implementation of the pattern for AdventureWorks to merge Department and Payment history for Employees:&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt;&lt;span style="color:#000000;"&gt; AllEvents &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
        EmployeeID      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;        OldValueOfRate  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfRate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;  
        OldValueOfDep   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfDep&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;   
        ChangeDate      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate     
    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                EmployeeID      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                OldValueOfRate  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Rate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfDep   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 DepartmentID
                                     &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeDepartmentHistory V
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;StartDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; PayHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;RateChangeDate
                                      &lt;/span&gt;&lt;span style="color:#808080;"&gt;AND&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; PayHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;StartDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; RateChangeDate 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeePayHistory PayHistory
        &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;UNION ALL&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                EmployeeID      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                OldValueOfRate  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 Rate
                                     &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeePayHistory V
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;RateChangeDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;StartDate
                                      &lt;/span&gt;&lt;span style="color:#808080;"&gt;AND&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;RateChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfDep   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;DepartmentID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; StartDate
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeDepartmentHistory DepHistory
        &lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events
    &lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DISTINCT
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    EmployeeID     &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate     &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfDep  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         OldValueOfDep&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepartmentID 
                           &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeDepartmentHistory DepHistory
                          &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; EndDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;IS&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;NULL&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                            &lt;/span&gt;&lt;span style="color:#808080;"&gt;AND&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; AllEvents&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;)),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfRate &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         OldValueOfRate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 Rate
                           &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeePayHistory PayHistory
                          &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; RateChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;))
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                    
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    AllEvents
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;By&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The code can be easily checked&amp;nbsp;filtering for&amp;nbsp;a single EmployeeID (4 is a good candidate for this check). Please note that - in this case&amp;nbsp;- the "current value" is kept in the history table and so the final COALESCE is a bit more intricated but still pretty easy both to write and to understand.&lt;/p&gt;
&lt;p&gt;If you have a better pattern for this kind of situation or any comments on it... I'll be glad to read your comments.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables&amp;amp;body=Seen on SQLblog.com: %0A%0A%09SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx" target="_blank" title = "Email SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx&amp;amp;title=SQL%3a+Merge+two+%26amp%3bquot%3bhistory+tracking%26amp%3bquot%3b+tables" target="_blank" title = "Submit SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx&amp;amp;phase=2" target="_blank" title = "Submit SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx&amp;amp;title=SQL%3a+Merge+two+%26amp%3bquot%3bhistory+tracking%26amp%3bquot%3b+tables" target="_blank" title = "Submit SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx&amp;amp;title=SQL%3a+Merge+two+%26amp%3bquot%3bhistory+tracking%26amp%3bquot%3b+tables" target="_blank" title = "Submit SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx&amp;amp;title=SQL%3a+Merge+two+%26amp%3bquot%3bhistory+tracking%26amp%3bquot%3b+tables&amp;amp;;top=1" target="_blank" title = "Add SQL: Merge two &amp;amp;quot;history tracking&amp;amp;quot; tables to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=2989" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx">SQL</category></item></channel></rss>