<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4685195631666212190</id><updated>2012-01-25T19:26:12.131-08:00</updated><category term='first'/><category term='about'/><category term='&quot;favorite blogs&quot;'/><title type='text'>Ruminations on Software</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://executioniseverything.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://executioniseverything.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>dmarkle</name><uri>http://www.blogger.com/profile/15358188036578831182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4685195631666212190.post-2075184602536681199</id><published>2007-08-19T15:24:00.001-07:00</published><updated>2007-08-20T19:13:40.128-07:00</updated><title type='text'>Why yes, I do a bit of Modeling...</title><content type='html'>&lt;p&gt;&amp;nbsp;  &lt;p&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image.png" atomicselection="true"&gt;&lt;img height="240" alt="image" src="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_thumb.png" width="174" align="right"&gt;&lt;/a&gt;One of my favorite sayings from Ben Franklin is "&lt;a href="http://usinfo.state.gov/usa/infousa/facts/loa/bf1758.htm" target="_blank"&gt;Experience is a dear teacher, but fools will learn at no other."&lt;/a&gt;&amp;nbsp;&amp;nbsp; True enough, but why, with the cornucopia of programming books, how-to articles, and blogs out there is experience &lt;em&gt;still&lt;/em&gt; such the dear teacher?&amp;nbsp;  &lt;p&gt;Mistakes.&amp;nbsp; Books, blogs, and &lt;a href="http://www.satisfice.com/blog/archives/27" target="_blank"&gt;best practices&lt;/a&gt; might tell us&amp;nbsp;how to perform a task, but sadly, little but experience shows us why&amp;nbsp;we &lt;em&gt;shouldn't&lt;/em&gt; do something else.&amp;nbsp; Someone recently asked me to review a database design, and I responded to this person with an admonition to "don't do that" and a friendly scowl.&amp;nbsp; Of course, the response was, "Why not?".&amp;nbsp; Here's the answer.  &lt;h4&gt;The Temptation of Surrogate Keys &lt;/h4&gt; &lt;p&gt;If you do enough database programming, you'll probably see that developers like IDENTITY (AutoNumber, for you Access people) columns as table primary keys.&amp;nbsp;&amp;nbsp;A lot.&amp;nbsp; In database language, this is referred to as a &lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/Surrogate_key" target="_blank"&gt;surrogate key&lt;/a&gt;&lt;/em&gt;.&amp;nbsp; Why?&amp;nbsp; Because they &lt;em&gt;seem&lt;/em&gt; to simplify database design and they seem to make it easy to query for single values on a table.&amp;nbsp; But if you aren't careful, you'll get into a heap of trouble, and it'll be hell to dig yourself out.  &lt;h4&gt;Surrogate Key Fields on Many-to-Many Relationship Tables &lt;/h4&gt; &lt;p&gt;Let's say we're designing a budgeting system&amp;nbsp;for a company.&amp;nbsp; Remember that this is all for the sake of argument, I'm not trying to show you how to design a budgeting system.&amp;nbsp; My apologies to all you CPAs out there...  &lt;p&gt;There are three entities in the system, and a couple of simple business rules:  &lt;p&gt;Our Entities:  &lt;ul&gt; &lt;li&gt;&lt;strong&gt;Account:&lt;/strong&gt; If you don't know what an account is, I suggest reading &lt;a href="http://britneyspears.celebden.com/" target="_blank"&gt;someone else's blog&lt;/a&gt;.  &lt;li&gt;&lt;strong&gt;Department&lt;/strong&gt;: A grouping of people within a company, such as "Accounts Receivable", "Software Development", "HR"...  &lt;li&gt;&lt;strong&gt;Budget: &lt;/strong&gt;A&amp;nbsp;grouping of the amounts&amp;nbsp;assigned to each account in each department&amp;nbsp;for a period of time (say, a fiscal year).&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Our&amp;nbsp;Rules, for the sake of argument:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Only certain &lt;strong&gt;Account&lt;/strong&gt;s can be used in certain &lt;strong&gt;Department&lt;/strong&gt;s.&amp;nbsp; For example, "HR" isn't allowed to budget for "Sales Travel", but are allowed to budget for things like&amp;nbsp;"Staffing Advertisements".  &lt;li&gt;Only certain &lt;strong&gt;Account&lt;/strong&gt;s are valid for certain &lt;strong&gt;Budget&lt;/strong&gt;s. Maybe certain accounts are retired as the company restructures its budgeting process, and others are introduced.&amp;nbsp; &lt;/li&gt;&lt;/ol&gt; &lt;h4&gt;Let's Start Designing (Badly)!&lt;/h4&gt; &lt;p&gt;So let's start designing!&amp;nbsp;&amp;nbsp;For this first round,&amp;nbsp;we'll design the system such that every table in the database has&amp;nbsp;a surrogate key.&amp;nbsp; To keep&amp;nbsp;the diagrams simple, we'll leave off the attributes of each entity and just show the keys. First off, let's implement Business Rule #1 with our &lt;strong&gt;Account&lt;/strong&gt; and &lt;strong&gt;Department&lt;/strong&gt; entities.&amp;nbsp;&amp;nbsp; We'll do this by using a relationship table called AllowableAccounts and two foreign keys:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_3.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_4.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="243" alt="Constraining Accounts to Departments" src="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_thumb_3.png" width="320" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Now for Business Rule #2.&amp;nbsp; We'll implement this one the same way:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_5.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_6.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="192" alt="image" src="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_thumb_4.png" width="320" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Now, for the final relationship -- the "Line Item" entry portion.&amp;nbsp; This is where we enter in the amount budgeted for each account, for each budget.&amp;nbsp; You get a &lt;a href="http://www.youtube.com/watch?v=1dmVU08zVpA" target="_blank"&gt;gift&lt;/a&gt; if you can already see where I'm going with this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_7.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_8.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_9.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_10.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="390" alt="image" src="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_thumb_5.png" width="500" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;There are a couple of things to note here.&amp;nbsp; There is a foreign key relationship between &lt;strong&gt;LineItem&lt;/strong&gt; and the &lt;strong&gt;DepartmentAccount&lt;/strong&gt; and &lt;strong&gt;BudgetableAccount&lt;/strong&gt; tables.&amp;nbsp; Notice that there are no references to BudgetID or AccountID in the &lt;strong&gt;LineItem&lt;/strong&gt; table.&amp;nbsp; This design seems to implement our business rules.&amp;nbsp; Unfortunately, there's a fatal flaw. &lt;/p&gt; &lt;h5&gt;There's no Relationship Between Budget, Account, and Department&lt;/h5&gt; &lt;p&gt;Here's the problem: LineItem does not enforce the rule that the AccountID referred to in &lt;strong&gt;BudgetableAccount&lt;/strong&gt; is the &lt;em&gt;same&lt;/em&gt; as the AccountID referred to for a given &lt;strong&gt;DepartmentAccount&lt;/strong&gt;.&amp;nbsp; It's therefore possible to run these queries against the database and return &lt;em&gt;different&lt;/em&gt; results:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font face="Courier New"&gt;SELECT AccountID c&lt;br&gt;FROM LineItem li &lt;br&gt;INNER JOIN BudgetableAccount bi&lt;br&gt;&amp;nbsp;ON bi.BudgetAccountID = li.BudgetAccountID&lt;br&gt;WHERE li.LineItemID = 5;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;font face="Verdana"&gt;and:&lt;/font&gt; &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font face="Courier New"&gt;SELECT AccountID c&lt;br&gt;FROM LineItem li &lt;br&gt;INNER JOIN DepartmentAccount di&lt;br&gt;&amp;nbsp;ON di.DepartmentAccountID = li.DepartmentAccountID&lt;br&gt;WHERE li.LineItemID = 5;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;font face="Verdana"&gt;This is possible because you don't have&amp;nbsp;direct relationship between Budget, Account, and Department.&amp;nbsp; What would happen if the data were up-to-date and someone were to update the &lt;strong&gt;DepartmentAccount&lt;/strong&gt; or &lt;strong&gt;BudgetAccount&lt;/strong&gt; tables to a different AccountID?&amp;nbsp; What if your business logic did not check this constraint before inserting?&lt;/font&gt;&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;h4&gt;There are Other Reasons, too&lt;/h4&gt; &lt;p&gt;First off, consider how you're going to be using the database.&amp;nbsp; Will you ever be querying off of DepartmentAccountID?&amp;nbsp; BudgetAccountID?&amp;nbsp; These fields have no business meaning, so you'll probably have to use a join in order to look up these columns.&amp;nbsp; This will probably mean when asking questions like, "What's the total amount budgeted for Budget X?" -- That requires a join across 2 tables -- and all for such a basic question.&amp;nbsp; Yuck.&amp;nbsp; &lt;/p&gt; &lt;h4&gt;A Better Design&lt;/h4&gt; &lt;p&gt;Instead of the previous design, let's eliminate the surrogate keys on the &lt;strong&gt;BudgetableAccount&lt;/strong&gt; and &lt;strong&gt;DepartmentAccount&lt;/strong&gt; tables, and create a relationship table for our LineItems based solely on the Budget, Department, and Account IDs.&amp;nbsp; Note that this design requires the use of 2-way composite foreign keys -- you can't just&amp;nbsp;use one column to create your relationship, you must create a foreign key using &lt;em&gt;both&lt;/em&gt; the Department/Account and Budget/Account key combinations.&amp;nbsp; &lt;em&gt;This is the key point that most beginning database programmers miss.&lt;/em&gt;&amp;nbsp; These special foreign key relationships are shown in blue:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_11.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_12.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_13.png" atomicselection="true"&gt;&lt;/a&gt;&lt;a href="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_14.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="362" alt="image" src="http://www.markleconsulting.com/blog-images/WhyYesIdoabitofModeling_A297/image_thumb_6.png" width="500" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;h4&gt;Conclusion &lt;/h4&gt; &lt;p&gt;Watch out for surrogate keys in relationship tables.&amp;nbsp; Avoid them when at all possible entirely -- they're meaningless from the context of your business.&amp;nbsp; Some object-relational frameworks force you to have a surrogate key on every table.&amp;nbsp; Perhaps you work in an environment where your DBA's or your "senior developers" mandate this practice, and you can't stop the madness. &amp;nbsp;Fine.&amp;nbsp; Just do yourself a favor -- &lt;em&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;don't define relationships based on a surrogate key in your relationship tables&lt;/font&gt;&lt;/strong&gt;.&amp;nbsp; &lt;/em&gt;It's a recipe for data integrity nightmares.&amp;nbsp; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4685195631666212190-2075184602536681199?l=executioniseverything.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://executioniseverything.blogspot.com/feeds/2075184602536681199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4685195631666212190&amp;postID=2075184602536681199&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/2075184602536681199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/2075184602536681199'/><link rel='alternate' type='text/html' href='http://executioniseverything.blogspot.com/2007/08/why-yes-i-do-bit-of-modeling.html' title='Why yes, I do a bit of Modeling...'/><author><name>dmarkle</name><uri>http://www.blogger.com/profile/15358188036578831182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4685195631666212190.post-1133654802573583216</id><published>2007-06-01T17:47:00.001-07:00</published><updated>2007-06-05T06:02:10.069-07:00</updated><title type='text'>Boycott TestDriven.NET!</title><content type='html'>&lt;div style="font-weight: bold; font-size: 130%;"&gt;&lt;br /&gt;        The Flap&lt;/div&gt;&lt;br /&gt;    I must say, there are very few times when something on the web makes me so angry I lose sleep over it, but &lt;a href="http://weblogs.asp.net/nunitaddin/"&gt;Jamie Cansdale&lt;/a&gt; has finally found a way. I'll assume that you've read all about the flap between Jamie and Microsoft regarding Visual Studio.NET Express and the TestDriven.NET add-in. Unfortunately, most of the buzz on the web is pretty "pro-Jamie" and "anti-MS". Of course. I expect that. The "borg" icon of Bill Gates on Slashdot, Product Activation, the software that costs more than $0 to install. Microsoft must be the bad guy here...    &lt;br /&gt;    &lt;div style="font-weight: bold; font-size: 130%;"&gt;&lt;br /&gt;        Jamie Quells Dissent on his Blog&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    You probably won't hear me paraphrase Chuck D much on this blog, but &lt;span style="font-style: italic;"&gt; don't believe the &lt;a href="http://www.publicenemy.com/index.php?page=page5&amp;item=9&amp;amp;num=42"&gt; hype&lt;/a&gt;. &lt;/span&gt;Why not? Well, I as well as &lt;a href="http://pluralsight.com/blogs/craig/archive/2007/05/31/47581.aspx"&gt; others (see Eric's post)&lt;/a&gt; have tried to write entries in his blog telling him that he's in the wrong on this issue. Somehow our posts never made it to his blog! Surprise! I wonder if it's a bug in his blogging engine. Or perhaps Jamie doesn't want to have a backlash against him start on his own weblog.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style='color:red'&gt;Update: Jamie responds in the comments below.  All comments should be visible.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;div style="font-weight: bold;font-size:130%"&gt;&lt;br /&gt;        TestDriven.NET is not Free Software&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    If you read most of the &lt;a href="http://developers.slashdot.org/developers/07/06/01/164254.shtml"&gt; responses&lt;/a&gt; to this story in Slashdot, or (believe it or not) &lt;a href="http://weblogs.asp.net/nunitaddin/archive/2007/05/31/microsoft-vs-testdriven-net-31-may-2007.aspx"&gt; Jamie's&lt;/a&gt; blog, you'll probably be led to believe that TestDriven.NET is free, open-source software, and that Jamie Cansdale is a lone developer, toiling away for the sake of the community, and being bullied by the 800 pound Gorilla that is Microsoft. Nothing could be further from the truth. TestDriven.NET costs&lt;a href="http://www.testdriven.net/purchase_pro.aspx"&gt;$95&lt;/a&gt; per user. Want an &lt;a href="http://www.testdriven.net/purchase_ent.aspx"&gt;enterprise license&lt;/a&gt;? That'll be $10,500, please. Some have made the patently ludicrous claim that Jamie does give the software away for free. Not if you're using it professionally, he doesn't! His licensing terms are... wait... that's the next section! Stay with me here, this is the best part!&lt;br /&gt;    &lt;div style="font-weight: bold; font-size: 130%;"&gt;&lt;br /&gt;        Jamie's License is Just as Bad&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    It's time to play a little game, boys and girls. The game is, "let's guess whose license agreement this is":&lt;br /&gt;    &lt;blockquote style="font-style: italic;"&gt;&lt;br /&gt;        ...you may use the software only as expressly permitted int his agreement. In doing so you must comply with any technical limitations in the software that only allow you to use it in certain ways... You may not work around any technical limitations in the software&lt;/blockquote&gt; versus:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;...Licensee shall not, and shall not permit others to ... use the Software in any manner not expressly authorised by this Agreement.&lt;/blockquote&gt;&lt;br /&gt;Sound pretty familiar, don't they. The same clause that Jamie complains is vague, irrelevant, and unenforceable in the MS license is pretty much exactly the same in the TestDriven.NET license. Jamie Cansdale is a hypocrite, and he deserves to be exposed as such, and punished.&lt;br /&gt;    &lt;div style="font-weight: bold;font-size:130%"&gt;&lt;br /&gt;        TestDriven.NET's Real Functionality comes from Software that &lt;i&gt;is&lt;/i&gt; Free&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    For those of you unfamiliar with the product, TestDriven.Net is basically a plug-in for Visual Studio that allows developers to run NUnit, MBUnit, and NCover tests with a click of the mouse, or a quick keystroke. It performs a few other functions, but that's about it. These products are all open-source and free. Others have labored long and hard to generate these tools, and Jamie ships them with his non-free product. All of the heavy lifting is done by these utilities -- TestDriven.NET is a convenience product that makes using them easier.&lt;br /&gt;    &lt;div style="font-weight: bold;font-size:130%"&gt;&lt;br /&gt;        Boycott TestDriven.NET&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    It all adds up to one thing -- Jamie Cansdale is using the publicity he's generated to line his pockets. If you are a developer of NUnit, NCover, or any other product that he exploits, I suggest that you either demand your fair share of his revenues or withdraw your permission for him to distribute your work with TestDriven.NET. Ever noticed that his site never got "slashdotted" in all of this brouhaha? He's ready for your orders, folks! Step right up! Gee, I wonder how many copies he's sold already. How about a disclosure there? Somehow I doubt we'll ever see it.&lt;br /&gt;    &lt;div style="font-weight: bold;font-size:130%"&gt;&lt;br /&gt;        My Prediction&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    Jamie is going to wait this out for a bit while the orders come rushing in due to this being the "hot topic" in the developer community.  Once he's satisfied that he's done that, he'll withdraw his plugin for Express, claiming that he's finally been beaten by the big, bad monster of Microsoft.  Microsoft will be happy that this PR nightmare is over, and will let Jamie off the hook.  And you-know-who laughs all of the way to the bank.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4685195631666212190-1133654802573583216?l=executioniseverything.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://executioniseverything.blogspot.com/feeds/1133654802573583216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4685195631666212190&amp;postID=1133654802573583216&amp;isPopup=true' title='35 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/1133654802573583216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/1133654802573583216'/><link rel='alternate' type='text/html' href='http://executioniseverything.blogspot.com/2007/06/boycott-testdrivennet.html' title='Boycott TestDriven.NET!'/><author><name>dmarkle</name><uri>http://www.blogger.com/profile/15358188036578831182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>35</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4685195631666212190.post-3120281693434410525</id><published>2007-01-01T17:03:00.000-08:00</published><updated>2007-01-01T18:22:45.421-08:00</updated><title type='text'>ORDER BY in Views: A SQL Server 2005 Gotcha!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_0EqMc5bjL9s/RZmyrfHVPbI/AAAAAAAAAAM/-Kx2w6vmvzs/s1600-h/satanflanders.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://2.bp.blogspot.com/_0EqMc5bjL9s/RZmyrfHVPbI/AAAAAAAAAAM/-Kx2w6vmvzs/s320/satanflanders.jpg" alt="" id="BLOGGER_PHOTO_ID_5015236120210128306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sqlblog.com/blogs/hugo_kornelis/default.aspx"&gt;Hugo Kornelis&lt;/a&gt; just &lt;a href="http://sqlblog.com/blogs/hugo_kornelis/archive/2006/12/31/Beatles-vs-Stones.aspx#comments"&gt;brought up&lt;/a&gt; a very interesting point about SQL Server 2005, and its behavior when using views with ORDER BY clauses in them.&lt;br /&gt;&lt;br /&gt;You may be aware that SQL Server 2000 (and previous versions) allowed you to essentially create an ordered view -- something that's not really supposed to be allowed -- simply by using TOP 100 PERCENT:&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;CREATE&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;VIEW&lt;/span&gt; myView &lt;span style="color:blue;"&gt;AS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;SELECT&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;TOP&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;100 &lt;span style="color:blue;"&gt;PERCENT&lt;/span&gt; LastName&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;FROM&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;dbo&lt;span style="color:gray;"&gt;.&lt;/span&gt;Stones&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;ORDER&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;BY&lt;/span&gt; LastName&lt;span style="color:gray;"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;In fact, this is exactly what Enterprise Manager, and as Hugo points out, Management Studio , does when you define a sorted view with the query designer (truly a tool of the Devil himself).&lt;br /&gt;&lt;br /&gt;When I do a&lt;span style="font-family:courier new;"&gt; &lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;&lt;br /&gt;SELECT &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;* &lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;FROM&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; dbo.myView&lt;/span&gt;;&lt;myview&gt;&lt;br /&gt;in SQL Server 2005 I get the following results:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Wyman&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Jones&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Watts&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Richards&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Jagger&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As you can imagine, this will break any query you have in your databases which rely on this "feature".  The truly amazing thing is that SQL Server Management Studio still allows users to choose a sort order in views without so much as a warning dialog box!&lt;br /&gt;&lt;br /&gt;So I wonder... Would this be considered a bug in the query parser, if it allows syntax that can't possibly work?   Is it a bug in the engine?  Should this evil trick still work?  All of this got me to thinking (uh oh) -- how could one work around this issue if one is upgrading a legacy database?&lt;br /&gt;&lt;br /&gt;And, what if you were to create the view like this?&lt;br /&gt;&lt;/myview&gt;        &lt;p class="MsoNormal" style=""&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;font-size:100%;"  &gt;CREATE&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;VIEW&lt;/span&gt; myView &lt;span style="color:blue;"&gt;AS&lt;/span&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;font-size:100%;"  &gt;SELECT&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;TOP&lt;/span&gt; (99.9999999999999) &lt;span style="color:blue;"&gt;PERCENT&lt;/span&gt; LastName&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;font-size:100%;"  &gt;FROM&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;dbo&lt;span style="color:gray;"&gt;.&lt;/span&gt;Stones&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;font-size:100%;"  &gt;ORDER&lt;/span&gt;&lt;span style=""&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;font-size:100%;"  &gt; &lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;color:blue;"   &gt;BY&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt; LastName&lt;/span&gt;&lt;span style="color:gray;"&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;;&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;myview&gt;Lo and behold, it "works" -- when you query the view, the results are shown in order.  But add just &lt;span style="font-style: italic;"&gt;one more nine&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;/myview&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;CREATE&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;VIEW&lt;/span&gt; myView &lt;span style="color:blue;"&gt;AS&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;SELECT&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;TOP&lt;/span&gt; (99.9999999999999&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;9&lt;/span&gt;) &lt;span style="color:blue;"&gt;PERCENT&lt;/span&gt; LastName&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;FROM&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;dbo&lt;span style="color:gray;"&gt;.&lt;/span&gt;Stones&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;&lt;br /&gt;ORDER&lt;/span&gt;&lt;span style=""&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt; &lt;/span&gt;&lt;span style=";font-family:courier new;color:blue;"  &gt;BY&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; LastName&lt;/span&gt;&lt;span style="color:gray;"&gt;&lt;span style="font-family:courier new;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;myview&gt;and you're back to the unordered list.   Strange.  I suppose that the SQL Server engine is doing a bit of rounding internally and throwing away the sort order altogether as an optimization so it won't have to perform a final sort on the resultset for no reason.   I really have no way to know exactly, though.&lt;br /&gt;&lt;br /&gt;Think setting the compatibility mode to &lt;span style="font-weight: bold;"&gt;80&lt;/span&gt; will save you?  Think again.  This behavior is independent of the compatibility mode you use.&lt;br /&gt;&lt;br /&gt;The moral of the story:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Before migrating your databases to SQL Server 2005, make sure you have no TOP 100 PERCENT ... ORDER BYs in your views.&lt;br /&gt;&lt;br /&gt;Analyze every query you run which consumes views with TOP 100 PERCENT ... ORDER BYs, and make sure they're ready for the new behavior.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;(This behavior is consistent both in SQL 2005 SP1 as well as the SQL 2005 SP2 Community Technology Preview)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-family:arial;"&gt;(Photo by &lt;/span&gt;&lt;a style="font-family: arial;" href="http://www.flickr.com/photos/frenkieb/"&gt;FRANKIEB&lt;/a&gt;&lt;span style="font-family:arial;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/myview&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4685195631666212190-3120281693434410525?l=executioniseverything.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://executioniseverything.blogspot.com/feeds/3120281693434410525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4685195631666212190&amp;postID=3120281693434410525&amp;isPopup=true' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/3120281693434410525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/3120281693434410525'/><link rel='alternate' type='text/html' href='http://executioniseverything.blogspot.com/2007/01/order-by-in-views-sql-server-2005.html' title='ORDER BY in Views: A SQL Server 2005 Gotcha!'/><author><name>dmarkle</name><uri>http://www.blogger.com/profile/15358188036578831182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_0EqMc5bjL9s/RZmyrfHVPbI/AAAAAAAAAAM/-Kx2w6vmvzs/s72-c/satanflanders.jpg' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4685195631666212190.post-6241806234859192794</id><published>2006-12-29T18:58:00.000-08:00</published><updated>2006-12-29T19:27:59.976-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='about'/><category scheme='http://www.blogger.com/atom/ns#' term='first'/><category scheme='http://www.blogger.com/atom/ns#' term='&quot;favorite blogs&quot;'/><title type='text'>What this is all About</title><content type='html'>Welcome to my first blog ever, "Execution is Everything".&lt;br /&gt;&lt;br /&gt;This site is about all things related to the discipline of software engineering and software development.  You'll see an eclectic mix of process topics, front-end design and implementations, and database-related articles.&lt;br /&gt;&lt;br /&gt;I feel that before I begin, I need to give you some promises.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No personal stuff.  I won't be blogging on my vacations.  You won't ever see baby pictures here.   I won't be talking about my hair or "that really cute girl at work/on the Metro/etc".&lt;br /&gt;&lt;/li&gt;&lt;li&gt;No politics.  I don't even care if you work for &lt;a href="http://en.wikipedia.org/wiki/You_Only_Move_Twice"&gt;Globex Corporation&lt;/a&gt; --  I won't judge you.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I will moderate comments here.  &lt;span style="font-style: italic;"&gt;Constructive&lt;/span&gt; criticism is encouraged.  I'll do my best to keep the signal-to-noise ratio here as high as possible, even in the comment section.&lt;/li&gt;&lt;li&gt;I will try to post once every week or two.  I guess that's not really a promise.  Hey, you get what you pay for.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;To get all of this stuff out of the way, let me share with you some of my favorite blogs.  You should check these out:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.pluralsight.com/blogs/default.aspx"&gt;PluralSight's blogs&lt;/a&gt;: These are some of the most experienced folks in the industry.  Keith Brown's security articles are always on the top of my must-read list.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://thedailywtf.com/Default.aspx"&gt;TheDailyWTF.com&lt;/a&gt;:  If you can't learn from your mistakes, at least learn from these guys.  The content seems to be slowing down, but I still check it out from time to time.  You should too.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.codinghorror.com/blog/"&gt;Coding Horror&lt;/a&gt;: Jeff Atwood always has something interesting to say about the industry -- and more often than not, the folks commenting on his site can be quite thought-provoking.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/"&gt;Joel on Software&lt;/a&gt;: He may have &lt;a href="http://www.codinghorror.com/blog/archives/000679.html"&gt;jumped the shark&lt;/a&gt;, but we still love him anyway.&lt;/li&gt;&lt;li&gt;&lt;a href="http://world.std.com/%7Ejlr/doom/doom_eng.htm"&gt;Doomed Engineers&lt;/a&gt;: OK, it's not really a live blog, but it's always nice to know that it could be worse.&lt;/li&gt;&lt;li&gt;&lt;a href="http://sqlblog.com/"&gt;SQLBlog&lt;/a&gt;: It's worth checking out periodically just because the illustrious &lt;a href="http://sqlblog.com/blogs/kalen_delaney/default.aspx"&gt;Kalen Delaney&lt;/a&gt; posts there.  If any one author has paid my grocery bills for the last five years, it's her.  &lt;a href="http://www.bookpool.com/sm/0735621055"&gt;&lt;span style="font-style: italic;"&gt;Inside SQL Server&lt;/span&gt;&lt;/a&gt; is one of my favorite technical books of all time, and gives an enormous amount of insight into what's inside the "black box" of SQL Server.  I've come to believe over the last few years that if you haven't read this book, you probably aren't a SQL Server expert.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4685195631666212190-6241806234859192794?l=executioniseverything.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://executioniseverything.blogspot.com/feeds/6241806234859192794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4685195631666212190&amp;postID=6241806234859192794&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/6241806234859192794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4685195631666212190/posts/default/6241806234859192794'/><link rel='alternate' type='text/html' href='http://executioniseverything.blogspot.com/2006/12/what-this-is-all-about.html' title='What this is all About'/><author><name>dmarkle</name><uri>http://www.blogger.com/profile/15358188036578831182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
