<?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>Search results matching tags 'sql server', 'SQL 2008', 'SHA-1', 'SHA-512', 'SHA-2', and 'sql 2005'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=sql+server,SQL+2008,SHA-1,SHA-512,SHA-2,sql+2005&amp;orTags=0</link><description>Search results matching tags 'sql server', 'SQL 2008', 'SHA-1', 'SHA-512', 'SHA-2', and 'sql 2005'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Find a Hash Collision, Win $100</title><link>http://sqlblog.com/blogs/michael_coles/archive/2010/04/17/find-a-hash-collision-win-100.aspx</link><pubDate>Sat, 17 Apr 2010 21:38:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:24374</guid><dc:creator>Mike C</dc:creator><description>&lt;P&gt;Margarity Kerns recently published a very nice article at SQL Server Central on &lt;A href="http://www.sqlservercentral.com/articles/Data+Warehouse/69679/"&gt;using hash functions to detect changes&lt;/A&gt; in rows during the data warehouse load ETL process.&amp;nbsp; On the discussion page for the article I noticed a lot of the same old arguments against using hash functions to detect change.&amp;nbsp; After having this same discussion several times over the past several months in public and private forums, I've decided to see if we can't put this argument to rest for a while.&amp;nbsp; To that end I'm going to hold a little contest:&amp;nbsp; &lt;B&gt;Generate an SHA-1 hash collision and win $100 and a book&lt;/B&gt; (see bottom section for details).&amp;nbsp; Before I get into the details of the contest I'm going to give a little background of how this came about.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;&lt;U&gt;Background Info&lt;/U&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;NOTE: If you aren't familiar with hash functions I highly recommend first reading the Wikipedia article at &lt;A href="http://en.wikipedia.org/wiki/Cryptographic_hash_function"&gt;http://en.wikipedia.org/wiki/Cryptographic_hash_function&lt;/A&gt;.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The idea of using a hash function for change detection is not new.&amp;nbsp; Essentially a hash function generates a "fingerprint" of your data that you can use to compare an inbound row and an existing row.&lt;/P&gt;
&lt;P&gt;Some people are wary of hash functions because they map a theoretically infinite number of large inputs to a much smaller finite set of hash values.&amp;nbsp; Most of the arguments people make against using hash functions for change detection boil down to variations of Murphy's Law:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;"There's a chance of a &lt;I&gt;hash&lt;/I&gt; &lt;I&gt;collision&lt;/I&gt; [generating the same hash value for two different inputs], so a collision &lt;I&gt;will&lt;/I&gt; happen!"&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;People have different ways of dealing with this issue, including taking one of the following positions:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The chance of collision is negligible so no additional precautions are required.&lt;/LI&gt;
&lt;LI&gt;A collision will absolutely happen so I won't use hash functions for change detection at all!&lt;/LI&gt;
&lt;LI&gt;A collision may happen so I want to use hash values only to initially narrow down the number of rows I need to compare fully.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Positions #1 and #2 above are at different ends of the spectrum.&amp;nbsp; Position #3 sits in the middle as a compromise solution.&amp;nbsp; While compromises may make for good politics, they often make for terrible technical solutions, as I'll discuss below.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;&lt;U&gt;Position #1: Odds of Collision are Low Enough to be Ignored&lt;/U&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;As far as position #1 is concerned, it depends on which hash function you're using.&amp;nbsp; You need to choose a true one-way &lt;I&gt;collision-free&lt;/I&gt;* cryptographic hash function with a wide bit length.&amp;nbsp; I normally recommend an SHA-2 hash function (256, 384 or 512 bit hash value), or when that's not available the SHA-1 160 bit hash function.&amp;nbsp; The odds of generating a collision with a 160 bit hash function are 2^80.&amp;nbsp; That is to say&amp;nbsp;you can expect a collision after you generate hashes for 1,208,925,819,614,629,174,706,176 rows of data.&lt;/P&gt;
&lt;P&gt;Of course if you're identifying rows by their natural or business keys this alternatively means you need to generate 1,208,925,819,614,629,174,706,176 variations of that single row before you'll hit a collision with SHA-1.&lt;/P&gt;
&lt;P&gt;To put that number in perspective, consider that Google processes 20,000,000,000,000,000 bytes (20 petabytes) of data per day.&amp;nbsp; If you were to store a single row in a database table for &lt;I&gt;every single byte&lt;/I&gt; Google processes each day, it would take you 60,446,290 days (approximately 156,600 years) to store 1,208,925,819,614,629,174,706,176 rows in that table.&lt;/P&gt;
&lt;P&gt;I personally assume position #1 on this subject, with the assumption that you have chosen a good solid hash function for the job.&amp;nbsp; More on this later.&lt;/P&gt;
&lt;P&gt;*A &lt;I&gt;collision-free&lt;/I&gt; cryptographic hash function is a one-way hash function with negligible probability of generating the same hash value for two different inputs. SHA-1 and SHA-256 are examples of collision-free cryptographic hash functions.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;&lt;U&gt;Position #2: I Don't Trust Hash Functions&lt;/U&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;This position can't really be argued with.&amp;nbsp; As shown above the odds of a collision with SHA-1 or another collision-free hash function are extremely low.&amp;nbsp; But if you don't trust it, you just don't trust it.&amp;nbsp; So the alternative is to compare every inbound column with every existing column.&amp;nbsp; It will cost you in efficiency on wide tables, but if you're not concerned about processing power, server resources&amp;nbsp;and execution time this classic method of change detection is well-proven to be 100% effective.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;&lt;U&gt;Position #3: The Compromise - Use Hash Values to Initially Narrow Down Results&lt;/U&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;This position is the compromise position that combines the implementation of #1 and #2 above.&amp;nbsp; It sounds wonderful in theory - use a hash function to narrow down your results, eliminating rows that don't need to be compared column by column; then compare all of the columns in the remaining rows that haven't been eliminated.&amp;nbsp; So let's look at a scenario:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;You are processing Row A through your ETL process into a target table. &amp;nbsp;Row B is the equivalent row in the target table (it has the same natural key/business key as Row A).&amp;nbsp; This assumes we are first locating the equivalent row in the target table by natural key/business key of the incoming row.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;There are three possible scenarios:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Row B exists in the target table, and is equal to Row A (no change).&lt;/LI&gt;
&lt;LI&gt;Row B exists in the target table, but it is not equal to Row A (update).&lt;/LI&gt;
&lt;LI&gt;Row B does not exist in the target table (insert Row A).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Let's say you've generated two hash values, h(A) is the hash for Row A and h(B) is the hash for Row B.&amp;nbsp; Now we need to use h(A) and h(B) to eliminate rows to get rid of the extra column by column comparisons.&amp;nbsp; Here are the rules you need to implement to use h(A) and h(B) to eliminate extra comparisons in this compromise solution:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;A.&amp;nbsp; &lt;STRONG&gt;h(A) is equal to h(B)&lt;/STRONG&gt;: according to the compromise, if h(A) = h(B) we need to compare all columns of the inbound row against the existing row since the belief is that the hash function can/will generate collisions.&amp;nbsp; The idea is that h(A) may have generated the same value as h(B) even if A &amp;lt;&amp;gt; B.&amp;nbsp; So we need to:&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;(1)&amp;nbsp; Compare all columns in A and B.&amp;nbsp; If A = B then perform no action.&lt;/P&gt;
&lt;P&gt;(2)&amp;nbsp; Compare all columns in A and B.&amp;nbsp; If A &amp;lt;&amp;gt; B then update.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;B.&amp;nbsp; &lt;STRONG&gt;h(A) is not equal to h(B)&lt;/STRONG&gt;: cryptographic hash functions guarantee that they will generate the same hash value for the exact same inputs.&amp;nbsp; So we can eliminate full row comparisons if h(A) &amp;lt;&amp;gt; h(B).&amp;nbsp; We know automatically that if h(A) &amp;lt;&amp;gt; h(B) then A &amp;lt;&amp;gt; B.&amp;nbsp; Just perform the update.&lt;/P&gt;
&lt;P&gt;C.&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;h(B) is NULL&lt;/STRONG&gt;: that is, if Row B does not exist in the target table than h(B) is NULL.&amp;nbsp; This is a case where no further full-row comparisons are necessary.&amp;nbsp; Just insert the row.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now consider a slowly changing dimension (SCD) in a datamart application.&amp;nbsp; Many SCDs change slowly over time (hence the name &lt;I&gt;slowly&lt;/I&gt; changing dimension).&amp;nbsp; This means that new rows (updates and inserts) are far less common than receiving duplicate rows during ETL.&amp;nbsp; So the vast majority of your inbound data will fall under rule A(1) above.&amp;nbsp; So you're still performing comparisons of all columns for the vast majority of rows in a given table just to figure out that you don't need to update them after all!&lt;/P&gt;
&lt;P&gt;If you eliminate even 90% of the inbound rows under rule A(1) above you haven't saved much processing (you're still comparing all columns for changes for 90% of your inbound rows).&amp;nbsp; You probably actually cost yourself a lot of time and efficiency since you haven't accounted for the overhead of generating hash values for 100% of the inbound rows.&lt;/P&gt;
&lt;P&gt;The only way this compromise is more efficient is if a very large percentage of your inbound rows (much greater than 50+%) are inserts under Rule C or updates under Rule B above.&amp;nbsp; If the majority of your inbound rows are duplicates of existing rows under Rule A, you gain nothing.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;&lt;U&gt;The Contest&lt;/U&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;One-way collision-free cryptographic hash functions are supposed to have negligible probability of a hash collision, or two different inputs generating the same output.&amp;nbsp; Hash collisions are what cause change detection with hashes to fail.&lt;/P&gt;
&lt;P&gt;For instance, consider the following example of an MD5 hash collision:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;DECLARE @A varbinary(8000),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @B varbinary(8000),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @hA binary(16),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @hB binary(16);&lt;BR&gt;&lt;BR&gt;SELECT @A = 0xd131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @B = 0xd131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70;&lt;BR&gt;&lt;BR&gt;SELECT @hA = HASHBYTES('MD5', @A),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @hB = HASHBYTES('MD5', @B);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;SELECT CASE WHEN @A = @B&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; THEN '@A Equals @B'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE '@A Is Not Equal To @B'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; END AS AB_Equal,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CASE WHEN @hA = @hB&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; THEN '@hA Equals @hB'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE '@hA Is Not Equal To @hB'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; END AS Hash_Equal;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The results are shown below:&lt;/P&gt;
&lt;P&gt;&lt;IMG style="WIDTH:474px;HEIGHT:130px;" src="http://e60ybw.bay.livefilestore.com/y1psxBkasfIDMgAHCMabS5PLB9ude1BiCrYSrlnX0bKKCpRgSTnMBYiy4gA2uLRjr5Tpf1Feki0LZ6WmJEDJiEl46UECVjVfPpt/hash_not_equal.png" width=474 height=130&gt;&lt;/P&gt;
&lt;P&gt;When you run this you'll notice that the query reports the two source varbinary strings @A and @B are not equal, yet the two MD5 hashes they generate are equal.&amp;nbsp; This is an example of a simple hash collision with MD5.&lt;/P&gt;
&lt;P&gt;Now the challenge is to populate the following script with two different binary values that generate the same hash value.&amp;nbsp; The output should be the same as shown above in the MD5 example.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;--&amp;nbsp; Begin script&lt;BR&gt;DECLARE @A varbinary(8000),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @B varbinary(8000),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @hA binary(20),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @hB binary(20);&lt;BR&gt;&lt;BR&gt;-- Replace the &lt;EM&gt;?&lt;/EM&gt; below with binary strings&lt;BR&gt;&lt;BR&gt;SELECT @A = &lt;EM&gt;?&lt;/EM&gt;,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @B = &lt;EM&gt;?&lt;/EM&gt;;&lt;BR&gt;&lt;BR&gt;SELECT @hA = HASHBYTES('SHA1', @A),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @hB = HASHBYTES('SHA1', @B);&lt;BR&gt;&lt;BR&gt;SELECT CASE WHEN @A = @B&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; THEN '@A Equals @B'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE '@A Is Not Equal To @B'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; END AS AB_Equal,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CASE WHEN @hA = @hB&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; THEN '@hA Equals @hB'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE '@hA Is Not Equal To @hB'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; END AS Hash_Equal;&lt;BR&gt;-- End script&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The first person who sends me an example of two varbinary strings that generate the same SHA1 hash value will win $100 (US$) and a copy of my book &lt;A href="http://www.amazon.com/T-SQL-2008-Programmer-rsquo-Guide/dp/143021001X"&gt;Pro T-SQL 2008 Programmer's Guide&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;And here are the inevitable conditions:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;B&gt;No NULLs.&lt;/B&gt;&amp;nbsp; @A and @B in the script above cannot be set to NULL for purposes of this contest.&lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;8,000 bytes or less.&lt;/B&gt;&amp;nbsp; The T-SQL HASHBYTES function accepts varbinary(8000) values, so the values passed into it in this contest must be 8,000 bytes in length or less.&amp;nbsp; The values assigned to @A and @B above must be 8,000 bytes or less in length.&lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;No unnecessary changes to the script.&lt;/B&gt;&amp;nbsp; The only change allowed to the script above are the replacement of the question marks (?) with binary strings.&amp;nbsp; No other changes to the script are authorized.&lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;Only one person will win.&lt;/B&gt;&amp;nbsp; The first person who sends me a copy of the above script with two different binary values that generate an SHA-1 hash collision will win.&lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;Void where prohibited.&lt;/B&gt;&amp;nbsp; Obviously if contests like this aren't legal in your country, state, county, city, etc. then you can't take part.&amp;nbsp; Petition your government to make it legal :)&lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;Time limits.&lt;/B&gt;&amp;nbsp; Entries must be received prior to midnight U.S. Eastern Standard Time on October 31, 2010.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Decisions of the judge are final.&lt;/STRONG&gt;&amp;nbsp; For purposes of this contest that would be me.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;SQL Server 2005 or 2008.&lt;/STRONG&gt;&amp;nbsp; Entries must be runnable on&amp;nbsp;SQL Server 2005 and SQL Server 2008 Developer Edition, and the results must be reproducible.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;If a winning entry is received prior to the deadline, I'll post an update entry to the blog with the winning script and the name of the winner.&lt;/P&gt;</description></item></channel></rss>