<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Alberto Ferrari : SQL, SQL Server</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/SQL+Server/default.aspx</link><description>Tags: SQL, SQL Server</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>SSIS: living in a parallel world? Not yet...</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2008/09/14/ssis-living-in-a-parallel-world-not-yet.aspx</link><pubDate>Sun, 14 Sep 2008 19:57:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8899</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>4</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/8899.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=8899</wfw:commentRss><description>&lt;P&gt;Today I come into a nice bug (misfeature?) of SSIS 2008 and I'd like to share it with you. Let's start from the beginning:&lt;/P&gt;
&lt;P&gt;One of the keys to make something speedy is to parallelize it. In TableDifference I read from two inputs, compare them and produce several outputs for new, deleted, updated rows and so on. It is the classical "produce/consumer" paradigm that works fine in parallel, creating a consumer thread that compares rows and different threads to produce them. &lt;/P&gt;
&lt;P&gt;During the porting of the component in SQL 2008 I discovered that my code does not work as expected. It reads all the lines, then terminates abnormally without producing a single row of output. It took me a couple of hours and several coffes to discover the change in the way SSIS handles asyncronous components causing my bug.&lt;/P&gt;
&lt;P&gt;In order to make the problem easier to understand (for microsoft connect too), I produced the same behaviour with a much simpler script component. Imagine to have a script transformation that needs to make some very complex work on each row. You will end up with something like this:&lt;/P&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Input0_ProcessInputRow(Input0Buffer Row) {
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction(Row);
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (Row.EndOfRowset ()) {
           OutputBuffer.SetEndOfRowset ();
        }
    }&lt;/PRE&gt;
&lt;P&gt;But, if you have a 64 CPU computer. You can imagine to detach many threads, each one handling just one very complex function, in this way you will produce a massive parallel computation. Wow! The solution to get maximum speed would be this:&lt;/P&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Input0_ProcessInputRow(Input0Buffer Row) {
        Thread T = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Thread(SendAsyncRow);
        T.Start(Row.EndOfRowset());
    }

    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SendAsyncRow(Object O) {
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction();
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; ((&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt;)O == &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;) {
            Output0Buffer.SetEndOfRowset();
        }
    }&lt;/PRE&gt;
&lt;P&gt;You detach a separate thread for each row, the thread will compute the very complex function and send it to the output buffer as soon as it is ready. In order to make SSIS understand when everything is finished, you signal SetEndOfRowset in the last thread.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;Don't start crying, this code will never work, the SetEndOfRowset is called on the last read line and not on the last produced one, but this is just pseudocode to understand the topic, don't blame me for inconsistencies. :) Let's go on with the main topic.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Under SSIS 2005 this code (in VB, of course) would work fine as the engine detects the end of processing when it receives the EndOfRowset on the outputs. In SSIS 2008 the engine detects the end of the processing as soon as the &lt;EM&gt;&lt;STRONG&gt;last call to ProcessInputRow has finished&lt;/STRONG&gt;&lt;/EM&gt;. So, in our case, after the last thread has been detached SSIS believes that the processing is finished and calls the cleaning up of the component, completely ignoring both the presence of separate threads running and our williness to not terminate the component because we know that we need some more time.&lt;/P&gt;
&lt;P&gt;The result? As with any other parallel bug you will sometime get a crash, on the same inputs sometime finish corectly, sometime get an error... the nightmare of any programmer.&lt;/P&gt;
&lt;P&gt;If you want to try it by yourself, cut and paste this code to a transformation script in a data flow that process some lines ( rows 10/20 lines are enough):&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Data;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.SqlServer.Dts.Pipeline.Wrapper;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.SqlServer.Dts.Runtime.Wrapper;

&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Threading;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; ScriptMain : UserComponent {

    &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; useThreads = &lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;;

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Processes input rows&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;param name="Row"&amp;gt;&amp;lt;/param&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Input0_ProcessInputRow(Input0Buffer Row) {
        Thread T = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Thread(SendAsyncRow);

        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (useThreads) {
            T.Start(Row.EndOfRowset());
        } &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt; {
            SendRow();
        }
    }

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Sends a row in sync mode&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SendRow() {
        &lt;SPAN class=rem&gt;// Thread.Sleep(100);&lt;/SPAN&gt;
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction();
    }

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Sends a row in async mode&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;param name="O"&amp;gt;&amp;lt;/param&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SendAsyncRow(Object O) {
        Thread.Sleep(100);
        Output0Buffer.AddRow();
        Output0Buffer.LineID = VeryComplexFunction();
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; ((&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt;)O == &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;) {
            Output0Buffer.SetEndOfRowset();
        }
    }

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Not very complex... but it's a demo!&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; VeryComplexFunction() {
        &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; 10;
    }
}&lt;/PRE&gt;
&lt;P&gt;using Serial mode (useThreads se to false) everything works fine. Using parallel mode (useThreads set to true) SSIS will crash and produce no output at all. The bug in TableDifference was very similar to that, I needed to handle the wait for termination of the consumer process during the ProcessInput function.&lt;/P&gt;
&lt;P&gt;It is not the first time I discover inconsistencies in the way SSIS handles parallelism, in order to try to make it easier to write code (using 2008 mode there is no need to call SetEndOfRowset and your program will run fine if you forget it) the architects of SSIS introduce a behavior that will make better and correct code crash. If you believe this is a problem, vote &lt;A href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=367692" target=_blank&gt;here&lt;/A&gt;, anyway... be aware of it, it mighe be useful in the future. :)&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8899" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/Components/default.aspx">Components</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx">SQL</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SSIS/default.aspx">SSIS</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/TableDifference/default.aspx">TableDifference</category></item><item><title>Visio and SQL Extended Properties: a tool to marry them</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/11/07/visio-and-sql-extended-properties-a-tool-to-marry-them.aspx</link><pubDate>Wed, 07 Nov 2007 10:00:32 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:3233</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>4</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/3233.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=3233</wfw:commentRss><description>&lt;p&gt;Visio database models have column descriptions, SQL Server has extended properties where to store them but, even if they share the same producer, it seems that Visio is unable to store column descriptions in extended properties so that other tools can gather the same information easily and produce a decent documentation of a database.&lt;/p&gt; &lt;p&gt;After some browsing on the web, I was unable to find a tool that let&amp;nbsp;Visio save the table and column descriptions in SQL Server, so I decided it was time to code it by myself.&lt;/p&gt; &lt;p&gt;First&amp;nbsp;you need to generate the DDL script of the database having DDL Script commens ON for all the columns (which can be configured in the driver options) as in the following picture:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;a href="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/VisioandExtendedPropertiesatooltomarryth_D6C3/Tp_1.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="394" alt="Tp" src="http://sqlblog.com/blogs/alberto_ferrari/WindowsLiveWriter/VisioandExtendedPropertiesatooltomarryth_D6C3/Tp_thumb_1.png" width="354" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;In the DDL file, VISIO adds header of comments to each table like this:&lt;/p&gt; &lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;/* Create new table "Sales.Dim_Customers".                                         */
/* "Sales.Dim_Customers" : Contains all the customer with various attributes used  */
/* to analyze them. Does not contain (bla bla bla)                                 */
/* "ID_Customer" : Primary key of the table                                        */
/* "CustomerCode" : Customer code as seen in the OLTP database                     */
/* "ID_Geography" : Key in Dim_Geography. It is not shown to the end user          */
/* "MaritalStatus" : Description of the marital status (Single / Married)          */
/* "Gender" : Description of the gender (Male, Female)                             */
&lt;/span&gt;&lt;span style="color:#808080;"&gt;...&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;...&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;...
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;create&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;table&lt;/span&gt;&lt;span style="color:#000000;"&gt; "Sales.Dim_Customers" &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
"ID_Customer" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;identity&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"CustomerCode" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;nvarchar&lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;15&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"ID_Geography" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"MaritalStatus" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;nvarchar&lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;20&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;"Gender" &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;nvarchar&lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;20&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;not&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;null)&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;I have written a simple parser (&lt;strong&gt;GenerateExtendedAttrib&lt;/strong&gt;) that looks for comments in this form in a DDL file (starting with "Create new table", then checks for column names and so on)&amp;nbsp;and will finally generate the sp_addextendedproperty calls to define all the column and table descriptions. &lt;/p&gt;
&lt;p&gt;The code fragment above generates this:&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;EXEC&lt;/span&gt;&lt;span style="color:#000000;"&gt; sys.sp_addextendedproperty 
    @name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'MS_Description'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @value&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Contains all the customer with various attributes used to analyze...'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level0type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'SCHEMA'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level0name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Sales'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level1type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'TABLE'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level1name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Dim_Customers'&lt;/span&gt;&lt;span style="color:#808080;"&gt;;
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;EXEC&lt;/span&gt;&lt;span style="color:#000000;"&gt; sys.sp_addextendedproperty 
    @name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'MS_Description'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @value&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Primary key of the table'&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level0type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'SCHEMA'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level0name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Sales'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level1type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'TABLE'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level1name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'Dim_Customers'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
    @level2type&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'COLUMN'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    @level2name&lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt;N&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'ID_Customer'&lt;/span&gt;&lt;span style="color:#808080;"&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;You can call the utility with "/Append" in order to have the property definitions appended to the original file (which, in turn, can be run to have the database created) or you can call it without parameters, in this case the code is written to the console and you can redirect it wherever you want.&lt;/p&gt;
&lt;p&gt;The tool can be downloaded at &lt;a href="http://www.sqlbi.eu"&gt;www.sqlbi.eu&lt;/a&gt;&amp;nbsp;and is provided with sources (it is indeed a very simple yet effective gadget) so you can adapt it to whatever your needs are.&lt;/p&gt;
&lt;p&gt;Have fun and, if you make any change to the code that might be useful, send me a note so I can update the public release.&lt;/p&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=3233" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx">SQL</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx">SQL Server</category></item><item><title>SQL: Merge two &amp;quot;history tracking&amp;quot; tables</title><link>http://sqlblog.com/blogs/alberto_ferrari/archive/2007/10/15/sql-merge-two-history-tracking-tables.aspx</link><pubDate>Mon, 15 Oct 2007 18:36:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:2989</guid><dc:creator>AlbertoFerrari</dc:creator><slash:comments>5</slash:comments><comments>http://sqlblog.com/blogs/alberto_ferrari/comments/2989.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/alberto_ferrari/commentrss.aspx?PostID=2989</wfw:commentRss><description>&lt;p&gt;If you&amp;nbsp;have two columns in a table that "remember" their old values in two different historical tables, as it is the case in AdventureWorks with EmployeePayHistory and EmployeeDepartmentHistory, you may need (or just wonder how) to merge these two tables into only one historical table that will keep track of both columns. &lt;/p&gt; &lt;p&gt;This&amp;nbsp;has been my "problem of the day" and, after some thoughts, I came up with a pattern of solution that I'd like to share with you both to see if you have a better solution and to have the code at hand when I'll need later. :)&lt;/p&gt; &lt;p&gt;Before using the real table, I made up a simple test case with a Product table with only two fields a couple of variation tables (VariationA and VariationB):&lt;/p&gt; &lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  Sample table Products, only two columns A and B. The current value of the row is (D, 4)
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt;&lt;span style="color:#000000;"&gt; Products &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    A &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CHAR&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;1&lt;/span&gt;&lt;span style="color:#808080;"&gt;),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    B &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT
&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt;&lt;span style="color:#000000;"&gt; products &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;A&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; B&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'D'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 4&lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  Variations for column A
--
--      ------------------
--      Year    Old Value
--      ------------------
--      2001        A
--      2002        B
--      2003        C
--      2005        D
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;   
    Position &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValue &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VARCHAR&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;5&lt;/span&gt;&lt;span style="color:#808080;"&gt;),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DATETIME&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;1&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'A'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2001'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;2&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'B'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2002'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;3&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'C'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2003'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;4&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'D'&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2005'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  Variations for column B
--
--      ------------------
--      Year    Old Value
--      ------------------
--      2000        1
--      2003        2
--      2004        3
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;   
    Position &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValue &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INT&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DATETIME&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;)

&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;1&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2000'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;2&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 2&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2003'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;Position&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;3&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 3&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff0000;"&gt;'01/01/2004'&lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The query that mixes all these variations into a single table is pretty easy but it took me some time to discover.&amp;nbsp;My solution is to detect what was the value of "B" when a variation in "A" happened and vice versa. As the values stored are "old" values, we know that the value of&amp;nbsp;A at a certain date is the value&amp;nbsp;stored in the first variation for&amp;nbsp;A AFTER that date. The only special case is the current time: if no variation record is found then we know that the value to use is the current value of the record in the product table. The same is obviously true for B.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I ended up with this&amp;nbsp;pattern query:&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#008000;"&gt;--
--  AllEvents contains all the events from both VariationA and VariationB,
--  and will detect, for each variation that happened, what was
--  the value of the other column at that time, building in this way the
--  merged variation list.
--  The final SELECT will return the sorted and DISTINCTed result. 
--  Then final COALESCE is needed because if a value is NULL it 
--  means that it should contain the "current" value of the column
--
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt;&lt;span style="color:#000000;"&gt; AllEvents &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
        OldValueOfA  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfA&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#008000;"&gt;-- Old value of A
&lt;/span&gt;&lt;span style="color:#000000;"&gt;        OldValueOfB  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfB&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#008000;"&gt;-- Old value of B
&lt;/span&gt;&lt;span style="color:#000000;"&gt;        ChangeDate   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate      &lt;/span&gt;&lt;span style="color:#008000;"&gt;-- Date of change
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfA &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfB &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 OldValue 
                                 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB V
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA 
        &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;UNION ALL&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfA &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 OldValue 
                                 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationA V
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate
                                &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfB &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; OldValue&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; VariationB
        &lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events
    &lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DISTINCT
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfA  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfA&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; A &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; Products&lt;/span&gt;&lt;span style="color:#808080;"&gt;)),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfB  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfB&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; B &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; Products&lt;/span&gt;&lt;span style="color:#808080;"&gt;))
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    AllEvents
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;By&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Clearly, i could have written some VB code in SSIS to solve the same problem. Nevertheless, having a pattern query at hand is useful because the pattern can be easily adapted to any real world situation with only&amp;nbsp;SQL Management Studio&amp;nbsp;at hand. The following code is the implementation of the pattern for AdventureWorks to merge Department and Payment history for Employees:&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt;&lt;span style="color:#000000;"&gt; AllEvents &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
        EmployeeID      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;        OldValueOfRate  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfRate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;  
        OldValueOfDep   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;OldValueOfDep&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt;   
        ChangeDate      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;ChangeDate     
    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                EmployeeID      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                OldValueOfRate  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; Rate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfDep   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 DepartmentID
                                     &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeDepartmentHistory V
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;StartDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; PayHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;RateChangeDate
                                      &lt;/span&gt;&lt;span style="color:#808080;"&gt;AND&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; PayHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;StartDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; RateChangeDate 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeePayHistory PayHistory
        &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;UNION ALL&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                EmployeeID      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                OldValueOfRate  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 Rate
                                     &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeePayHistory V
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;RateChangeDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;StartDate
                                      &lt;/span&gt;&lt;span style="color:#808080;"&gt;AND&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID
                                    &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; V&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;RateChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;),&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                OldValueOfDep   &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;DepartmentID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                ChangeDate      &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; StartDate
            &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeDepartmentHistory DepHistory
        &lt;/span&gt;&lt;span style="color:#808080;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt; Events
    &lt;/span&gt;&lt;span style="color:#808080;"&gt;)
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;DISTINCT
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    EmployeeID     &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    ChangeDate     &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfDep  &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         OldValueOfDep&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepartmentID 
                           &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeDepartmentHistory DepHistory
                          &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt;&lt;span style="color:#000000;"&gt; EndDate &lt;/span&gt;&lt;span style="color:#808080;"&gt;IS&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;NULL&lt;/span&gt;&lt;span style="color:#000000;"&gt; 
                            &lt;/span&gt;&lt;span style="color:#808080;"&gt;AND&lt;/span&gt;&lt;span style="color:#000000;"&gt; DepHistory&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; AllEvents&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;)),
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    OldValueOfRate &lt;/span&gt;&lt;span style="color:#808080;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;COALESCE&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#808080;"&gt;(
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         OldValueOfRate&lt;/span&gt;&lt;span style="color:#808080;"&gt;,
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                         &lt;/span&gt;&lt;span style="color:#808080;"&gt;(&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt;&lt;span style="color:#000000;"&gt; 1 Rate
                           &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt;&lt;span style="color:#000000;"&gt; HumanResources&lt;/span&gt;&lt;span style="color:#808080;"&gt;.&lt;/span&gt;&lt;span style="color:#000000;"&gt;EmployeePayHistory PayHistory
                          &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt;&lt;span style="color:#000000;"&gt; RateChangeDate&lt;/span&gt;&lt;span style="color:#808080;"&gt;))
&lt;/span&gt;&lt;span style="color:#000000;"&gt;                    
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;FROM
&lt;/span&gt;&lt;span style="color:#000000;"&gt;    AllEvents
&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;By&lt;/span&gt;&lt;span style="color:#000000;"&gt; EmployeeID&lt;/span&gt;&lt;span style="color:#808080;"&gt;,&lt;/span&gt;&lt;span style="color:#000000;"&gt; ChangeDate
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The code can be easily checked&amp;nbsp;filtering for&amp;nbsp;a single EmployeeID (4 is a good candidate for this check). Please note that - in this case&amp;nbsp;- the "current value" is kept in the history table and so the final COALESCE is a bit more intricated but still pretty easy both to write and to understand.&lt;/p&gt;
&lt;p&gt;If you have a better pattern for this kind of situation or any comments on it... I'll be glad to read your comments.&lt;/p&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=2989" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL/default.aspx">SQL</category><category domain="http://sqlblog.com/blogs/alberto_ferrari/archive/tags/SQL+Server/default.aspx">SQL Server</category></item></channel></rss>