<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Alberto Ferrari</title><subtitle type="html" /><id>http://sqlblog.com/blogs/alberto_ferrari/atom.aspx</id><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/default.aspx" /><link rel="self" type="application/atom+xml" href="http://sqlblog.com/blogs/alberto_ferrari/atom.aspx" /><generator uri="http://communityserver.org" version="2.1.61129.1">Community Server</generator><updated>2007-04-08T09:48:26Z</updated><entry><title>SQLBI: Yet Another DWH Methodology?</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/27/sqlbi-yet-another-dwh-methodology.aspx</id><published>2008-09-26T21:21:56Z</published><updated>2008-09-26T21:21:56Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author></entry><entry><title>SSIS: living in a parallel world? Not yet...</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx</id><published>2008-09-14T19:57:00Z</published><updated>2008-09-14T19:57:00Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author><category term="SQL Server" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx" /><category term="TableDifference" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/TableDifference/default.aspx" /><category term="SSIS" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSIS/default.aspx" /><category term="Components" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Components/default.aspx" /><category term="SQL" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx" /></entry><entry><title>Reading zip files with SSIS</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/07/16/reading-zip-files-with-ssis.aspx</id><published>2008-07-16T16:25:53Z</published><updated>2008-07-16T16:25:53Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author></entry><entry><title>TableDifference version 2.0 has been released</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/02/22/tabledifference-version-2-0-has-been-released.aspx</id><published>2008-02-22T12:45:07Z</published><updated>2008-02-22T12:45:07Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author></entry><entry><title>Table Difference 2.0 - Call for beta</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/12/17/table-difference-2-0-call-for-beta.aspx</id><published>2007-12-17T11:53:37Z</published><updated>2007-12-17T11:53:37Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author><category term="TableDifference" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/TableDifference/default.aspx" /><category term="SSIS" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSIS/default.aspx" /><category term="Components" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Components/default.aspx" /></entry><entry><title>SSIS Multicast and Trash or Separate and Union?</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/15/ssis-multicast-and-trash-or-separate-and-union.aspx</id><published>2007-11-15T12:15:22Z</published><updated>2007-11-15T12:15:22Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author><category term="SSIS" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSIS/default.aspx" /></entry><entry><title>Visio and SQL Extended Properties: a tool to marry them</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx</id><published>2007-11-07T10:00:32Z</published><updated>2007-11-07T10:00:32Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author><category term="SQL Server" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx" /><category term="SQL" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx" /></entry><entry><title>SQL: Merge two &amp;quot;history tracking&amp;quot; tables</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx</id><published>2007-10-15T18:36:00Z</published><updated>2007-10-15T18:36:00Z</updated><content type="html">&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;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author><category term="SQL Server" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx" /><category term="SQL" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx" /></entry><entry><title>Dimensional modeling with Ranged Dimensions</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2007/09/06/dimensional-modeling-with-ranged-dimensions.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/09/06/dimensional-modeling-with-ranged-dimensions.aspx</id><published>2007-09-06T06:55:16Z</published><updated>2007-09-06T06:55:16Z</updated><content type="html">&lt;p&gt;A ranged dimension is a dimension that is used to have a discrete view of a continuous measure. &lt;p&gt;A good example of this is the analysis of amount sold per order. In AdventureWorks we have, for each line of an order, the amount and quantity sold. We would like to divide orders in three groups (HIGH, MEDIUM, LOW) based on the total of the order. This is a very frequent kind of analysis that is used to determine how much money customers are willing to spend in a single order and may be very useful to check whether there is any kind of relationship between the characteristics of a customer and his/her medium spending capability. &lt;p&gt;In SQL it is very easy to get this analysis: &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;    OrderTotals &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; 
            SalesOrderId &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; SalesOrderId&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            OrderValue   &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;SUM&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;OrderQty &lt;/span&gt;&lt;span style="color:#808080;"&gt;*&lt;/span&gt;&lt;span style="color:#000000;"&gt; UnitPrice&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; 
            Sales&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;SalesOrderDetail
        &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;GROUP&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;            SalesOrderId&lt;/span&gt;&lt;span style="color:#808080;"&gt;),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OrdersRanged &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;            SalesOrderId&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;            OrderValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;            OrderRange &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;CASE
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt;&lt;span style="color:#000000;"&gt; OrderValue &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;lt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1000  &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'LOW'
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt;&lt;span style="color:#000000;"&gt; OrderValue &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;lt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; 10000 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'MEDIUM'
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ELSE&lt;/span&gt;&lt;span style="color:#000000;"&gt;                          &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'HIGH'
&lt;/span&gt;&lt;span style="color:#000000;"&gt;            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;END
&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;            OrderTotals&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;    OrderRange  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; OrderRange&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    OrderNumber &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;COUNT&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;    OrderValue  &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;SUM&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;OrderValue&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;    OrdersRanged
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;GROUP&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;    OrderRange
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The query, executed on AdventureWorks, leads to this result:&lt;/p&gt;
&lt;table cellspacing="0" cellpadding="2"&gt;

&lt;tr&gt;
&lt;td&gt;OrderRange&lt;/td&gt;
&lt;td&gt;OrderNumber&lt;/td&gt;
&lt;td&gt;OrderValue&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;1,827&lt;/td&gt;
&lt;td&gt;75,745,964.3559&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;12,574&lt;/td&gt;
&lt;td&gt;31,075,706.5634&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LOW&lt;/td&gt;
&lt;td&gt;17,064&lt;/td&gt;
&lt;td&gt;3,552,218.3941&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;This SQL query is correct but what we really want to do is to create a new OrderRange dimension in our BI solution to let the user further analyze the characteristics of the orders. The granularity of this attribute is at the Order level and so we have to add an ID_ValueRange column in the fact table of orders.
&lt;p&gt;If we define the Dim OrderRange dimension we will get something like it:
&lt;ul&gt;
&lt;li&gt;ID_OrderRange Primary Key, usually INT IDENTITY&lt;/li&gt;
&lt;li&gt;MinimunValue Left value for the range &lt;/li&gt;
&lt;li&gt;MaximunValue Right value for the range&lt;/li&gt;
&lt;li&gt;OrderRange Textual description of the range&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;At the end of the processing, our relational database will look like this:
&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/DimensionalmodelingwithRangedDimensions_8B58/image.png"&gt;&lt;img height="151" alt="image" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/DimensionalmodelingwithRangedDimensions_8B58/image_thumb.png" width="640" border="0"&gt;&lt;/a&gt; 
&lt;p&gt;This solution is good when we have a very clear definition of what the ranges are during design time. This often does not happen in the real world. More likely, we will let the user define ranges through a table in the configuration database and we will define several attributes and hierarchies in the dimension to analyze how orders are ranged. All these attributes and hierarchies should be derived from the configuration database and processed during the ETL phase.
&lt;p&gt;Ranges are dimensions that have a high variation rate over time and – normally – they can be defined only after the data is available because, before then, users do not have a clear understanding of what kind of ranges can be useful or not.
&lt;p&gt;This leads to a very annoying problem i.e. the ranges can be determined only at the cube process time and not at ETL time. In other words we are not able to compute the ID_OrderRange key used to join the dimension to the fact table because the ranges change over time due to the user change of mind. Please note that in this case it is the dimension that changes its meaning, not the facts.
&lt;p&gt;Computing the ranges during cube process time will lead us to define queries for the fact table that are complicated and uselessly consume processor time. So the challenge is to avoid this situation by means of changing the dimensional model.
&lt;p&gt;The solution that we recommend is to define ranged dimensions with a different surrogate key. Even if we are not able to define the exact ranges, we can normally define the maximum granularity that will be used to define ranges. In the example the granularity can be 1,000, but it can be more cleverly set to 100 in order to gain some flexibility at the lowest level of the range. Supposing that 100,000 is the maximum value of an order (at least from the DSS analyst point of view), we will have a maximum range of values that starts at 100 and ends at 100,000 with a step of 100, leading to a range of only 1,000 different values. This will be the Dim OrderRange dimension.
&lt;p&gt;Once we have defined the granularity we can redefine the Dim_OrderRange assigning to ID_OrderRange a simple INTEGER field that represents the value of FLOOR (OrderRange / 100). The same value, computed for each column of the order fact table, will be the ID used to join the fact table to the dimension.
&lt;p&gt;The dimension will contain all the values from 0 to the maximum order value divided by the granularity and so it will be larger but&amp;nbsp;still contain only a few thousand rows. In our example the table switched from 3 values to 1,000 but, from SSAS point of view, it is still a very small dimension. Moreover, as the distinct values of the attributes&amp;nbsp;are still three, the aggregation will work very well leading to optimum performances.
&lt;p&gt;The situation, with ranged dimensions, will be this:
&lt;p&gt;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/DimensionalmodelingwithRangedDimensions_8B58/image_1.png"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="334" alt="image" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/DimensionalmodelingwithRangedDimensions_8B58/image_thumb_1.png" width="640" border="0"&gt;&lt;/a&gt; 
&lt;p&gt;Using the ranged dimension pattern you will be able to change all the attributes of the ranged dimension without having to worry about changes. The fact table will remain valid unless you decide to change the granularity.
&lt;p&gt;Granularity is not subject to changes because it can be normally set to a value clearly defined by the user and there is very rarely the need of updating it.
&lt;p&gt;Clearly ranged dimensions are a variation of standard dimension because their surrogate key has a clear meaning while the surrogate keys, in Kimball’s methodology, should not have any meaning at all. Nevertheless, we believe that in specific situation (and ranged dimension are among those) the “no meaning at all” constraint can be relaxed in order to get maximum flexibility in the final solution the customer will use.
&lt;p&gt;Another very common situation where ranged dimension are useful is in the ranging of time duration. When handling time you can easily set the granularity to days, months, years or seconds, depending on the minimum and maximum values that the duration will have. Once done it you can compute the duration using the correct granularity and define any ranged dimension on it.&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=Dimensional modeling with Ranged Dimensions&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Dimensional modeling with Ranged Dimensions%0A%0Ahttp://sqlblog.com/blogs/alberto_ferrari/archive/2007/09/06/dimensional-modeling-with-ranged-dimensions.aspx" target="_blank" title = "Email Dimensional modeling with Ranged Dimensions"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/alberto_ferrari/archive/2007/09/06/dimensional-modeling-with-ranged-dimensions.aspx&amp;amp;title=Dimensional+modeling+with+Ranged+Dimensions" target="_blank" title = "Submit Dimensional modeling with Ranged Dimensions 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/09/06/dimensional-modeling-with-ranged-dimensions.aspx&amp;amp;phase=2" target="_blank" title = "Submit Dimensional modeling with Ranged Dimensions 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/09/06/dimensional-modeling-with-ranged-dimensions.aspx&amp;amp;title=Dimensional+modeling+with+Ranged+Dimensions" target="_blank" title = "Submit Dimensional modeling with Ranged Dimensions 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/09/06/dimensional-modeling-with-ranged-dimensions.aspx&amp;amp;title=Dimensional+modeling+with+Ranged+Dimensions" target="_blank" title = "Submit Dimensional modeling with Ranged Dimensions 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/09/06/dimensional-modeling-with-ranged-dimensions.aspx&amp;amp;title=Dimensional+modeling+with+Ranged+Dimensions&amp;amp;;top=1" target="_blank" title = "Add Dimensional modeling with Ranged Dimensions 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=2460" width="1" height="1"&gt;</content><author><name>AlbertoFerrari</name><uri>http://sqlblog.com/members/AlbertoFerrari.aspx</uri></author><category term="Dimensional Model" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Dimensional+Model/default.aspx" /><category term="Dimension" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Dimension/default.aspx" /><category term="Ranged" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Ranged/default.aspx" /><category term="SSAS" scheme="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSAS/default.aspx" /></entry><entry><title>How are GUIDs sorted by SQL Server?</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/alberto_ferrari/archive/2007/08/31/how-are-guids-sorted-by-sql-server.aspx" /><id>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/08/31/how-are-guids-sorted-by-sql-server.aspx</id><published>2007-08-31T14:19:07Z</published><updated>2007-08-31T14:19:07Z</updated><content type="html">&lt;p&gt;Today I ran into a nice&amp;nbsp;problem with SQL Server fancy way of sorting GUIDS.&lt;/p&gt; &lt;p&gt;I know, there should be no reason at all to sort GUID columns but, if what you need is run two tables side by side to check whether they are aligned or not&amp;nbsp;(this is the task of &lt;a href="http://www.sqlbi.eu/Default.aspx?tabid=74"&gt;TableDifference&lt;/a&gt;) and a GUID is the&amp;nbsp;best key you have, then you will end up sorting GUIDS. The question now is: how do you sort GUIDS? The fact is that SQL Server and .NET give different answers. Let's have a look at it in deeper detail.&lt;/p&gt; &lt;p&gt;I was using .NET guids to read data from SQL Server and then use .Compare to check for the sorting, supposing that a uniqueidentifier in SQL is sorted the same way a guid is sorted in .NET. &lt;/p&gt; &lt;p&gt;This is not true, I discovered &lt;a href="http://msdn2.microsoft.com/en-us/library/system.data.sqltypes.sqlguid(VS.71).aspx"&gt;here&lt;/a&gt; that you should use SqlGuid instead. Let's not spend too many words on why having two sort algorithm&amp;nbsp;may be&amp;nbsp;clever or not, what is&amp;nbsp;frightening about that article is the fact that it says that SqlGuid uses only the last six bytes to sort data. If&amp;nbsp;it's working this way then we will end up with a sorting algorithm that does not really sorts. Seemed to be too stupid, so I double checked it and ran into &lt;a href="http://blogs.msdn.com/sqlprogrammability/archive/2006/11/06/how-are-guids-compared-in-sql-server-2005.aspx"&gt;this&lt;/a&gt; that says something more interesting about how GUIDS are sorted. Anyway, the algorithm is not still clear. Will I end up with a completely sorted list if I issue an ORDER BY on a uniqueidentifier column? and, how will this data be sorted?&lt;/p&gt; &lt;p&gt;After all, the best way is always&amp;nbsp;that of&amp;nbsp;trying, so I end up with this very simple and funny query (that you can use to show friends that bits are still here, in 2007!):&lt;/p&gt;&lt;span style="color:#000000;"&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; UIDs &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:#008000;"&gt;--                         0 1 2 3  4 5  6 7  8 9  A B C D E F
&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; ID &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:#0000ff;"&gt;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0000-010000000000'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &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:#0000ff;"&gt;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0000-000100000000'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &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:#0000ff;"&gt;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0000-000001000000'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &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:#0000ff;"&gt;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0000-000000010000'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &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; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0000-000000000100'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;  6&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;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0000-000000000001'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;  7&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;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0100-000000000000'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;  8&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;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0000-0010-000000000000'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;  9&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;UID&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:#ff00ff;"&gt;cast&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;'00000000-0000-0001-0000-000000000000'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &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:#0000ff;"&gt;uniqueidentifier&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;Union&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; ID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; 10&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;UID&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="colo