<?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-4501041662390804509</id><updated>2012-02-16T05:24:05.679-08:00</updated><category term='visual studio'/><category term='bad cursors'/><category term='crystal reports'/><category term='avoiding cursors'/><category term='cursor alternative'/><category term='windows 7 64'/><category term='coalesce()'/><category term='recursion'/><category term='errors'/><category term='cte'/><title type='text'>GET YER DEAD HANDS OFF MY DATABASE</title><subtitle type='html'>databases, programming, the web, and the imminent zombie apocalypse</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-3131579599959082</id><published>2011-01-31T15:39:00.000-08:00</published><updated>2011-01-31T15:48:03.476-08:00</updated><title type='text'>101 LINQ TO SQL Code Samples</title><content type='html'>The following page has been heaven sent for quick access to LINQ TO SQL sample code.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you have trouble like I do memorizing the exact LINQ to SQL Syntax  (despite the fact that accomplishing the same thing in t-sql would be second nature) then you should appreciate the link as well.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://msdn.microsoft.com/en-us/vbasic/bb688085"&gt;http://msdn.microsoft.com/en-us/vbasic/bb688085&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I stumbled onto this link via this months SqlServerCentral "database weekly" newsletter.  The SSC article takes you to a C# version.  If you prefer the C# version then you should check here instead of the VB link above.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx"&gt;http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-3131579599959082?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/3131579599959082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2011/01/101-linq-to-sql-code-samples.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/3131579599959082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/3131579599959082'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2011/01/101-linq-to-sql-code-samples.html' title='101 LINQ TO SQL Code Samples'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-5597377622560076094</id><published>2010-10-14T11:17:00.000-07:00</published><updated>2010-10-14T11:44:03.565-07:00</updated><title type='text'>Crystal Reports for Visual Studio 2010 Deployment</title><content type='html'>There is currently no runtime for Crystal Report for Visual Studio 2010.  A quick Google search reveals this work around.  In short, go ahead and use the 2008 SP 2 runtime - it should work fine.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.sdn.sap.com/irj/sdn/go/portal/prtroot/docs/library/uuid/d085f103-ff2d-2d10-2f9e-ffb14d10ef33?QuickLink=index&amp;amp;overridelayout=true"&gt;http://www.sdn.sap.com/irj/sdn/go/portal/prtroot/docs/library/uuid/d085f103-ff2d-2d10-2f9e-ffb14d10ef33?QuickLink=index&amp;amp;overridelayout=true&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The one thing this workaround doesn't tell you is that you still have to go into your project references and set "most" of the CrystalDecisions assemblies to the 2008 sp 2 (12.2) version.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you don't do that your deployed application will give you the following error message:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Could not load file or assembly CrystalDecisions.Windows.Forms  with a reference to version 14 .####.##&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a quick snapshot of what my VS2010 applications that are using Crystal Reports references look like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://1.bp.blogspot.com/_ljPKsAnuHcY/TLdOx-aAD3I/AAAAAAAABO8/8JAvL08Ls9I/s400/assemblies.png" style="cursor:pointer; cursor:hand;width: 400px; height: 118px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5527973688093183858" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Notice that  the "Enterprise" assemblies remain version 14.  There is no corresponding 12.2 version and this didn't seem to keep my applications from working.  Also, as mentioned in a previous post - don't forget to set cpu for x86 if you are developing on a 64 bit machine.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-5597377622560076094?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/5597377622560076094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/10/crystal-reports-for-visual-studio-2010.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/5597377622560076094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/5597377622560076094'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/10/crystal-reports-for-visual-studio-2010.html' title='Crystal Reports for Visual Studio 2010 Deployment'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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://1.bp.blogspot.com/_ljPKsAnuHcY/TLdOx-aAD3I/AAAAAAAABO8/8JAvL08Ls9I/s72-c/assemblies.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-4635990303405292763</id><published>2010-08-12T08:32:00.000-07:00</published><updated>2010-08-12T11:35:12.777-07:00</updated><title type='text'>Installing Crystal Runtime With Your .Net Deployment</title><content type='html'>If any of your .Net projects contain Crystal Reports you’ve probably contemplated the confusing reality of deployment.  Getting those embedded reports to function on client computers like they do on your development box never seems as easy as it should be.  You have options including merge modules, separate runtime installs, and so on – but if your installs are going to be done by folks who are not familiar with your project or by end users whose technical skill is questionable you want your install to deploy as easy as possible.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That’s why for me… , my favorite solution for deployment projects that contain Crystal Reports is Visual Studio’s Custom Actions feature.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Custom Action’s allow you to run a separate executable as part of your install.  So if you have the appropriate run time installation from Crystal Reports in hand, you can include it in your Deployment Project.  If you don’t have the appropriate runtime installation for Crystal, chances are &lt;a href="https://websmp130.sap-ag.de/sap(bD1lbiZjPTAwMQ==)/bc/bsp/spn/bobj_download/main.htm"&gt;you can download it here&lt;/a&gt;.  (At least you could as of this post)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It’s pretty much as easy as this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. After you have set up your basic deployment project either from scratch or using the wizard right click on your deployment project and select ‘View File System’.  From here you need to add the Crystal Runtime package to the Application Folder (or somewhere else that makes sense to you).  Basically we just need to ensure the installer can find it later (as you'll see below).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://1.bp.blogspot.com/_ljPKsAnuHcY/TGQkSOjGz_I/AAAAAAAABN8/vJx7-HQ8jyU/s400/Add+File.png" style="cursor:pointer; cursor:hand;width: 400px; height: 165px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5504564540115177458" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;It's optional, but I would also suggest you set 'Exclude' to true under the file's properties in your deployment project (as shown below).  This will keep the runtime package from being copied to the end users app folder after the install is complete - which reduces the total footprint of your application and leaves less executables laying around for no reason.  Don't worry, the install package can still access the file even with 'exclude' marked true.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://4.bp.blogspot.com/_ljPKsAnuHcY/TGQ8P95a24I/AAAAAAAABOs/S3PF2GUifMA/s400/exclude.png" style="cursor:pointer; cursor:hand;width: 378px; height: 347px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5504590889564691330" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2.       Right click on your project again and select ‘View Custom Actions’. You’ll notice that you can add a custom action as part of the “Install” or as part of another process associated with the project such as Un-Install. For now, right click on Install and add it there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://2.bp.blogspot.com/_ljPKsAnuHcY/TGQkmYXu1VI/AAAAAAAABOE/MUorE330EG4/s400/Add+Custom+Action.png" style="cursor:pointer; cursor:hand;width: 357px; height: 315px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5504564886349206866" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://2.bp.blogspot.com/_ljPKsAnuHcY/TGQk2WxKyYI/AAAAAAAABOM/AS4N6WNRUdg/s400/custom+action.png" style="cursor:pointer; cursor:hand;width: 400px; height: 196px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5504565160796932482" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3.       After selecting Add Custom Action you will be prompted to select an executable (or script) from files that are already included in your project.  Open the file system folder where you placed the runtime (in step 1), highlight the runtime and click ‘Add’.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://4.bp.blogspot.com/_ljPKsAnuHcY/TGQlIpNvAqI/AAAAAAAABOU/NEkx9DxcEhg/s400/Select+Item.png" style="cursor:pointer; cursor:hand;width: 400px; height: 282px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5504565474986230434" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;img src="http://1.bp.blogspot.com/_ljPKsAnuHcY/TGQmgXKNftI/AAAAAAAABOk/4ELzJ7An5VM/s400/select+file.png" style="cursor:pointer; cursor:hand;width: 400px; height: 282px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5504566981968101074" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;4.       If necessary you can now customize the Crystal Runtime installation with any available command line arguments (under properties).  My current version of Crystal (Version 12 SP 2) has various command line options (which you can discover by running the install from the command line with the /? Switch).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;Note: For some reason my version of Visual Studio adds the switch "/install" into my argument box.  This doesn't do anything (in fact, it keeps it from running properly) so either leave it blank or add a known argument that you've tested.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://3.bp.blogspot.com/_ljPKsAnuHcY/TGQl0LF0RyI/AAAAAAAABOc/L2DReSK-xMg/s400/install+argument.png" style="cursor:pointer; cursor:hand;width: 303px; height: 224px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5504566222814201634" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;Two examples of common options you might pass as arguments. &lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt; /quiet   (Quiet mode, no user interaction) &lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt; /passive  (Unattended mode - progress bar only) &lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;It’s always a good idea to test your deployment but really, that should pretty much cover it.  When the end user installs your package, it will automatically install the Crystal Runtime as well without any additional user effort.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-4635990303405292763?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/4635990303405292763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/08/installing-crystal-runtime-with-your.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/4635990303405292763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/4635990303405292763'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/08/installing-crystal-runtime-with-your.html' title='Installing Crystal Runtime With Your .Net Deployment'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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://1.bp.blogspot.com/_ljPKsAnuHcY/TGQkSOjGz_I/AAAAAAAABN8/vJx7-HQ8jyU/s72-c/Add+File.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-5649179355638460950</id><published>2010-06-08T10:30:00.001-07:00</published><updated>2010-06-08T11:22:30.458-07:00</updated><title type='text'>SQL Server 2008 Sparse Column Generalities</title><content type='html'>&lt;div&gt;The following is a great guide on using the new Sparse Column feature of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;SQL&lt;/span&gt; Server 2008. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc280604.aspx"&gt;http://msdn.microsoft.com/en-us/library/cc280604.aspx&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It seems to me however that this entire article can be boiled down to a much simpler generality.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. Using sparse columns on bit, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;tinyint&lt;/span&gt; is pointless - &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;smallint&lt;/span&gt; is borderline.  &lt;/div&gt;&lt;div&gt;2. On the rest of the columns &lt;i&gt;that support sparse&lt;/i&gt; your only going to get decent space savings if more than 60% of your values are null.  &lt;/div&gt;&lt;div&gt;3. If your getting fancy with the columns, (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;filestream&lt;/span&gt;, replication, indexes, default values, identity etc.) then Sparse is most likely not going to work, or if it does - it probably isn't worth the administrative effort to maintain.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Like all generalities, there will be edge cases that wont apply to my generality.  I can only hold so much information in my head however, so it's the general rule I use for deciding whether or not to look deeper into using a Sparse column.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Where Sparse columns really shine is when you run into those non-normal legacy type tables that are as wide as they are long.  Tables that we lovingly describe as random in content.  If this describes a table you know - that you work with regularly - then you should also look into &lt;a href="http://msdn.microsoft.com/en-us/library/cc280521.aspx"&gt;Column Sets&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In a nutshell, Column Sets return all your Sparse Columns in a well formed XML block.  If you have a lot of matrix type queries that need to be performed - it can really be useful.  Especially if you can consume it's XML output for displaying query results in an ASP.Net page or if your preparing a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;JSON/AJAX&lt;/span&gt; solution.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Read up on column sets here &lt;a href="http://msdn.microsoft.com/en-us/library/cc280521.aspx"&gt;http://msdn.microsoft.com/en-us/library/cc280521.aspx&lt;/a&gt; .&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-5649179355638460950?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/5649179355638460950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/06/sql-server-2008-sparse-column.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/5649179355638460950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/5649179355638460950'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/06/sql-server-2008-sparse-column.html' title='SQL Server 2008 Sparse Column Generalities'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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-4501041662390804509.post-7779887446117998493</id><published>2010-06-04T14:02:00.000-07:00</published><updated>2010-06-04T15:08:01.712-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='crystal reports'/><category scheme='http://www.blogger.com/atom/ns#' term='windows 7 64'/><category scheme='http://www.blogger.com/atom/ns#' term='errors'/><title type='text'>Crystal Reports Error in VS 2008 on Windows 7 64</title><content type='html'>Ok, so my last post was way off my usual topics.  Probably not too many more posts on here about &lt;a href="http://www.durafaucet.com/"&gt;RV faucets and camping&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This one is more typical of the stuff I run into on a regular basis.  Crap I can't explain for a few hours and then finally lightning strikes, there is a eureka moment and then I move on.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A few months ago I upgraded my development machine to Win 7 64.  I ran into a couple gotcha's moving my visual studio projects off my old computer but for the most part it was a nice clean transition.  That was until this morning when I opened an old project that needed a couple features added.  Long story short, the project contains some crystal reports and when I compiled the project I suddenly started getting an error when attempting to view the report.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;An error has occurred while attempting to load the Crystal Reports runtime.  Either the Crystal Reports registry key permissions are insufficient or the Crystal Reports runtime is not installed correctly.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://2.bp.blogspot.com/_ljPKsAnuHcY/TAlsWWBdExI/AAAAAAAABM8/szpXfq-nFSs/s400/crystalerror.png" style="cursor:pointer; cursor:hand;width: 400px; height: 224px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5479029552797520658" /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well, that's just plain silly - I own the full blown Crystal Developer product and have it installed on my box.  What's more is my other projects use Crystal Reports embedded and they run no problem.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I checked in my list of references to make sure the dll's that were being referenced were the same.  They were.  I deleted those references anyway and recreated them from scratch.  No luck.  I excluded the report files from the project and then reattached them using 'Add Existing'. It no worky either.   I deleted the VB files related to the Crystal so the engine would regenerate them.  That didn't help.  I even tried actually installing the runtime package on my machine to see if that would fix anything and all it did was break my Crystal Developer install - (re-installing that was fun).  Well, my last hope was that after having to reinstall the full developer product the problem would surely go away.  ...  well, .... it didn't.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, I almost forgot ... I also discovered during this little adventure.  &lt;a href="http://www.sdn.sap.com/irj/boc/downloads"&gt;Crystal Reports 2008 Service Pack 3 is out&lt;/a&gt;.  And no, that didn't fix my error either.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After a few choice words with the cubicle air around me such as Crystal Reports is a flying piece of steamy crap - I finally realized what the issue was.  It all comes down to doing a thorough comparison between the ones that work and the ones that didn't.  This is what I found.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://3.bp.blogspot.com/_ljPKsAnuHcY/TAlvzumRlpI/AAAAAAAABNE/ZRgAkAnomP4/s400/x86.png" style="cursor:pointer; cursor:hand;width: 400px; height: 99px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5479033356145497746" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had forgotten that a lot of third party tools don't really want to run in 64 bit.  Crystal Reports is apparently one of these.  Under configuration manager when doing your project build you need to specify X86 as the platform instead of the default 'Any CPU'.  My other projects were already set this way because I was pushing the finished product to clients who were all on 32 bit Win XP machines.  Boom bam fixed it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-7779887446117998493?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/7779887446117998493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/06/crystal-reports-error-in-vs-2008-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7779887446117998493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7779887446117998493'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/06/crystal-reports-error-in-vs-2008-on.html' title='Crystal Reports Error in VS 2008 on Windows 7 64'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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/_ljPKsAnuHcY/TAlsWWBdExI/AAAAAAAABM8/szpXfq-nFSs/s72-c/crystalerror.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-6259294265449215140</id><published>2010-05-27T20:05:00.000-07:00</published><updated>2010-06-01T15:10:51.631-07:00</updated><title type='text'>Magento Customization Tricks and RV Faucets</title><content type='html'>&lt;div&gt;I've pretty much been a career Microsoft guy - SQL Server, .Net developer,... yep that's me - Mr corporate sell-out.  Last year however I was presented with an interesting problem.  I was asked to set up a shopping cart system but do it for free - or as close to free as possible.  My time isn't free so building one from scratch definitely wasn't the best solution.  The client also had an existing web hosting account that he hoped to be able to use.  So, now my requirements were free and based on linux, mysql, php.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, anyone else and I would have said, "go find some php hippie that'll do it for a Costco pallet &lt;/div&gt;&lt;div&gt;of Doritos and let me get back to my corporate strength big-boy tools".  But, the client is a friend of mine.  One I would rather keep - so he was warned that his request would require some research on my part and possible an unhappy ending.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Enter Magento.&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I don't remember exactly how I stumbled onto it but I started tinkering with &lt;a href="http://www.magentocommerce.com/"&gt;Magento&lt;/a&gt;.  I was encouraged that a lot of big name companies were happy to lend their logos and claim they liked it.  There were a few free templates floating around and we found one that fit the bill nicely.  It wasn't long before we had the site up and running and I have to admit.  I was pretty dang impressed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;b&gt;Enter Scope Creep&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It wasn't long before the client started asking questions like... "can you make it so that the product image changes to match the user option selected?" - and other seemingly simple requests. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If I had one true complaint about Magento it would be there is precious little developer documentation.  It's too new to simply pick up a cookbook at the local &lt;a href="http://www.powells.com/technicalbooks"&gt;tech friendly book store&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The core Magento product has a pretty incredible collection of source files.  Add any template files on top of that and the file count gets a little staggering.  My install had over 11,000 files associated with it.  That's a whole lot of javascript, php, classes, objects, etc etc etc that I didn't write and have no intimate knowledge of.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My other major problem with PHP is that I am used to Visual Studio intellisense - you know.... a tool that tells me all the methods, properties etc. of every object at my fingertips.  My PHP development is all in notepad - no intellisense.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Enter the two most useful tricks I have found for customizing Magento.&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;First&lt;/b&gt; - a way to discover the location of the code that needs fixin'.  Also known as &lt;a href="http://www.magentocommerce.com/blog/comments/template-path-hints-tutorial-video/"&gt;Template Path Hints&lt;/a&gt;.  Describing it would take too long, so just watch the &lt;a href="http://www.magentocommerce.com/blog/comments/template-path-hints-tutorial-video/"&gt;video in the link&lt;/a&gt;.  It's the same video I stumbled onto while pondering the problem.  Absolutely priceless trick.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Second&lt;/b&gt; - a way to discover the methods at your disposal within the source code that Template Path Hints helped you locate.  This is probably elementary level knowledge for you PHP / MySql hippies out there.  For me, it was a real life saver.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In my case I needed to locate the SKU of a configurable product so I could access the images associated with the simple child product.  I saw in the php code a variable called $this.  It was obvious from the way it was being used that it probably held the information I needed.  While trolling the &lt;a href="http://www.magentocommerce.com/boards/"&gt;magento forums&lt;/a&gt; for anyone else who had faced this same scenario I found this little block of code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://3.bp.blogspot.com/_ljPKsAnuHcY/S_9HbcIUHTI/AAAAAAAABM0/F8y3SP8gb7M/s1600/code.png"&gt;&lt;img src="http://3.bp.blogspot.com/_ljPKsAnuHcY/S_9HbcIUHTI/AAAAAAAABM0/F8y3SP8gb7M/s400/code.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5476174208638917938" style="cursor: pointer; width: 296px; height: 100px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In short, this prints to screen all the methods within the $this object.   I used it as instructed, and sure enough - right at the top of the list was a method called $this-&gt;getChildProduct().  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I set a variable equal to $this-&gt;getChildProduct() and ran the above code on that variable.  Again, right at the top of the list was another method.  $child-&gt;getThumbnailUrl().  Ok, it might be a simple block of code... but again, priceless.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, and by the way.  &lt;a href="http://www.durafaucet.com/"&gt;If you need an RV faucet for your motor home, or fifth wheel - you should really check out Dura Faucet&lt;/a&gt;.  They'll hook you up.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-6259294265449215140?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/6259294265449215140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/05/magento-customization-tricks-and-rv.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/6259294265449215140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/6259294265449215140'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/05/magento-customization-tricks-and-rv.html' title='Magento Customization Tricks and RV Faucets'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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://3.bp.blogspot.com/_ljPKsAnuHcY/S_9HbcIUHTI/AAAAAAAABM0/F8y3SP8gb7M/s72-c/code.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-7115198450955006328</id><published>2010-03-11T13:41:00.000-08:00</published><updated>2010-03-11T22:50:49.465-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursor alternative'/><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='avoiding cursors'/><category scheme='http://www.blogger.com/atom/ns#' term='bad cursors'/><category scheme='http://www.blogger.com/atom/ns#' term='cte'/><category scheme='http://www.blogger.com/atom/ns#' term='coalesce()'/><title type='text'>Cursors and the super hero community</title><content type='html'>&lt;div&gt;A few years ago I was interviewing for a position and the question came up... "What is a cursor and does it have value in SQL Server databases?"  I gave my definition and then regarding the second half of the question answered... "Every now and then a problem comes up where a cursor is literally the only possible solution.  If that's really the case, hey - it's a tool available to you.  If you can come up with &lt;i&gt;ANY&lt;/i&gt; other way to address the problem however - it's probably a better way".  The interviewer smiled and said, "yep, that's how I'd answer too".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To a SQL pro using a cursor is like Superman taking the stairs.  It's an affront to the whole super hero community.  Who does he think he is taking the stairs like some procedural based dBase language?  This is TSQL not FoxPro.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what are some good techniques to avoiding cursors?  Here are a few I've picked up along the way.  I'm sure countless others exist and I'd love to get comments with other techniques or approaches.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. Table Variable, Identity(1,1), and a little creativity&lt;/div&gt;&lt;hr /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I would say that most cursors I have seen could be replaced with a creative mixture of WHILE loops, temp tables, table variables, and/or user defined functions/sprocs.  SQL might be set based but the query language gives us a lot of tools to find and work with individual rows or fields.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Consider the following example.  I create a table variable with an identity key that starts at one.  This key allows me to then isolate each row one by one in a while loop.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;DECLARE @pImportantKey int&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;DECLARE @pNotACursor TABLE &lt;/div&gt;&lt;div&gt;(&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;AutoKey int IDENTITY(1,1),   &lt;span class="Apple-style-span"  style="color:#009900;"&gt;-- this is important&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;ImportantKey int, &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;EmpName varchar(50)&lt;/div&gt;&lt;div&gt;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;INSERT INTO @pNotACursor (ImportantKey, EmpName) &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;SELECT ImportantKey, EmpName &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;FROM Employees WHERE Salary &gt; 250000&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;DECLARE @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;pCount&lt;/span&gt; int&lt;/div&gt;&lt;div&gt;SET @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;pCount&lt;/span&gt; = 1&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;DECLARE @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;pRows&lt;/span&gt; int&lt;/div&gt;&lt;div&gt;SELECT @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;pRows&lt;/span&gt; = Count(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;ImportantKey&lt;/span&gt;) FROM @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;pNotACursor&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;WHILE @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;pCount&lt;/span&gt; &lt;= @pRows&lt;/div&gt;&lt;div&gt;BEGIN&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;SELECT @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;pImportantKey&lt;/span&gt; = &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;ImportantKey&lt;/span&gt; &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;&lt;/span&gt;FROM @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;pNotACursor&lt;/span&gt; WHERE &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;AutoKey&lt;/span&gt; = @pCount&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;EXEC &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;DoSomethingFancy&lt;/span&gt; @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;pImportantKey&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;SET @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;pCount&lt;/span&gt; = @pCount + 1&lt;/div&gt;&lt;div&gt;END&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;2. COALESCE() and Concatenation&lt;/span&gt;&lt;/div&gt;&lt;hr /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Most DB guys have run into a scenario where they have had to express columnar data in a single row.  Also known as making long data wide or pivoting.  A few of us may have thrown a cursor at the problem.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Most database developers came from programming backgrounds of some kind.  We brought foundational knowledge of loops and concatenation with us.  So, the cursor may be the first thing we'd think of to solve what comes to mind as a procedural problem.  At least that was my excuse when I wrote my first cursor.  It's also how I first discovered Coalesce for uses other than finding a non-null value.  I then hunted down and killed that first cursor.  In the words of Cpl Pearson, Generation Kill...  "Look, I'm a man now".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" color: rgb(0, 0, 102); white-space: pre-wrap; font-family:Courier, Verdana, Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms190349.aspx"&gt;COALESCE(expression [ ,...n ])&lt;/a&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"   style="  color: rgb(0, 0, 102); white-space: pre-wrap; font-family:Courier, Verdana, Arial, Helvetica, sans-serif;font-size:11px;"&gt;&lt;/span&gt;takes any number of arguments and simply returns the first non null, so how in the world does it help us here.  Let's look at the following code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's say that&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;Select [Region]&lt;br /&gt;FROM &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;SalesRegion&lt;/span&gt;&lt;br /&gt;WHERE &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;EmployeeKey&lt;/span&gt; = 12345&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;produces the following:&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;Delaware&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;Iowa&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;Ohio&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Let's run it again using Coalesce()&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;DECLARE @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;pResult&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;varchar&lt;/span&gt;(max)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;SELECT @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;pResult&lt;/span&gt; = COALESCE(@pResult + ', ', '') + [Region] &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;FROM &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;SalesRegion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;WHERE &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;EmployeeKey&lt;/span&gt; = 12345 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;SELECT @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;pResult&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;This time around we get the same data only it's been pivoted.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is how it works...  The first time @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;pResult&lt;/span&gt; is null so the second argument (the empty string) is returned by the function.  That's what Coalesce does.  The empty string is then concatenated with [Region] of the first &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;rowset&lt;/span&gt;. ''+'Delaware' results in 'Delaware'.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The second time Coalesce() is called @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;pResult&lt;/span&gt; is not null (it's equal to 'Delaware') so the first argument @&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;pResult&lt;/span&gt; is returned (and concatenated with ',').  This creates the result 'Delaware,' which is concatenated again with [Region] resulting in 'Delaware,Iowa'&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Without using a cursor we end up with the result set:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="color:#CC6600;"&gt;'Delaware, Iowa, Ohio'&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;3. RECURSION and Common Table Expressions&lt;/span&gt;&lt;/div&gt;&lt;hr /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another place you might be able to clean cursors out of your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;sprocs&lt;/span&gt; is by using recursion and the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;CTE&lt;/span&gt; structure.  I could eat up a bunch of space providing an example but unlike above where I'm using COALESCE() in a way that may be outside what the engineers originally intended, the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;CTE&lt;/span&gt; structure can clean up cursors when used exactly as it was intended.  So, I'll just refer you to the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;MSDN&lt;/span&gt; article  &lt;a href="http://msdn.microsoft.com/en-us/library/ms186243.aspx"&gt;Recursive Queries using Common Table Expressions&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Step through the sample provided at the bottom and I think you'll get the picture.  This could be a great tool for fighting the urge to use a cursor.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-7115198450955006328?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/7115198450955006328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/03/cursors-and-super-hero-community.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7115198450955006328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7115198450955006328'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/03/cursors-and-super-hero-community.html' title='Cursors and the super hero community'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-4199628753907890933</id><published>2010-03-04T12:28:00.000-08:00</published><updated>2010-03-09T12:19:47.658-08:00</updated><title type='text'>Why I always start with a temp table (vs table variable)</title><content type='html'>Most people who are serious enough about SQL Server Administration already understand the pro/con matrix of table variable vs temp tables.  A decent thread outlining the matrix can be &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/6698069d-7d1f-42e4-9136-7247842d3481"&gt;found on MSDN&lt;/a&gt; and any &lt;a href="http://odetocode.com/Articles/365.aspx"&gt;number of SQL blogs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I often find myself leaning towards temp tables for the simple fact that they are easier to script out.  I build my select statement as the logic pours for my brain and then simply add a " INTO #tblDestination " before the FROM clause and boom-bam a local temp table ready to be worked with.&lt;br /&gt;&lt;br /&gt;Inside I know that in most cases I should be using a table variable for performance and IO reasons but I still prefer to code it out as a temp table just because it's so much easier to write.  I don't have to pre-think the table design and struggle to declare it when I haven't fully explored the logic in the queries below that will create it.&lt;br /&gt;&lt;br /&gt;Before you judge me as reckless and lazy however... there is still method to my madness.&lt;br /&gt;&lt;br /&gt;After having written the procedure and tested its results as sound I go back and THEN give it some thought from a performance (temp vs variable) standpoint.&lt;br /&gt;&lt;br /&gt;If I decide a table variable would have been a better solution - no problem. I now have all my fields and datatypes defined in my query logic making it easy to declare the needed table variables using the logic below as a reference.  I am careful to name all the tables the same just using a @tblDestination where before I used a #tblDestination.&lt;br /&gt;&lt;br /&gt;As a coding rule my  " INTO #tblDestination " statements from the first go around are already on their own line (for readability and because I knew they might go away soon) so those are easy to delete.  Also, with my table declarations now written it is also much easier for me to add a " INSERT INTO @tblDestination (values)" above each statement that used to contain a " SELECT INTO " statement.&lt;br /&gt;&lt;br /&gt;As a final step a simple find and replace completes the conversion from #tblDestination to @tblDestination.&lt;br /&gt;&lt;br /&gt;Some people might find this method is not right for them.  My high school geometry teacher used to go nuts following my proofs (that were always right, mind you, they just contained a few logic paths that some might consider atypical).  Either way, best practice has been met and for me... starting with a temp table works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-4199628753907890933?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/4199628753907890933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/03/why-i-always-start-with-temp-table-vs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/4199628753907890933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/4199628753907890933'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/03/why-i-always-start-with-temp-table-vs.html' title='Why I always start with a temp table (vs table variable)'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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-4501041662390804509.post-4899098598850533783</id><published>2010-01-29T10:22:00.001-08:00</published><updated>2011-06-13T13:56:48.736-07:00</updated><title type='text'>SQL Server Migration Assistant 2008 for MySQL</title><content type='html'>&lt;span class="Apple-style-span" style="font-size:small;"&gt;A couple weeks ago I downloaded the &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=69739c8c-ac82-41de-b9e6-8fa5ae2594d9&amp;amp;displaylang=en"&gt;Microsoft Sql Server Migration Assistant&lt;/a&gt; for MySQL V1.0.  We have a handful of MySQL databases we've been putting off converting for the simple fact that it's always such a pain.  This morning however I was going over my zombie plan and realized a database containing the location of my tactical bacon was in MySQL.  I need it in SQL Server. I can't put this off any longer, time to try the new tool.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Listen in on my brain patterns as I re-live the experience:&lt;br /&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Start by installing SSMA on the same box that was hosting the MySQL tables.  Installed fine, add the license file, ok, no problem, (just follow the on-screen prompts).  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Alright, this looks very empty, nothing here.  Let's click "start a new project"... seems logical.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Really only presented with 2 toolbar buttons, 'Connect to MySQl' and 'Connect to SQL Server' ok let's start with MySQL.  Enter port, root, password, all familiar...  wait an error message.  'error occurred while collecting data.'&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;a href="http://3.bp.blogspot.com/_ljPKsAnuHcY/S2Mp0vKjpYI/AAAAAAAABKM/lCdP0xalnH0/s1600-h/clip_image002.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 295px; height: 140px;" src="http://3.bp.blogspot.com/_ljPKsAnuHcY/S2Mp0vKjpYI/AAAAAAAABKM/lCdP0xalnH0/s400/clip_image002.jpg" border="0" alt="error occurred while collecting data" id="BLOGGER_PHOTO_ID_5432231561529632130" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Ok... not very informative.  Google search, not much out there...  hey, a readme file that came with the SSMA download... maybe that will have something helpful.  Documentation says...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;span&gt;&lt;span&gt;----------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size:large;"&gt;3.0 Documentation Notes &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;span class="Apple-style-span" style="font-size:x-small;"&gt;There are currently no documentation notes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;----------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;div class="section" id="sectionSection3"&gt;&lt;content xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5"&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Hmmmm, well CTP release... I guess I can't really complain.  You gotta admire the Microsoft guys who took the time to enter this in the read-me file though.&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;I have another MySQL install I guess I'll move the files to it and try again.  Back up files, move them to MySQL on another box.  (first install was version 5.05.1, the second is 5.1).  This time it seemed to connect fine.  I wish I knew something more than "error occured" with regards to it not wanting to run on the 5.05.1 box.  Possibly an issue with the ODBC driver being 5.1 ???&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Ok, now let's connect to SQL Server...  fiddled around a little before figuring out that the connect button will not 'enable' until you've put something in the database field.  (even though I have no intention of actually using that database - after all, I'm connecting to migrate a database that doesn't exist in SQL Server yet)  Sure enough, once in - I can select any database on the server - not really sure why they want me to enter a database before letting me connect.  It doesn't even have to be a legitimate database.&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;So, both servers are now connected, I can browse schema's.... great, now what...  I don't really see anything obvious.  I've clicked the database I want to migrate.  I've added and clicked the database on the SQL side that I want to migrate to.  Well,   Maybe it's voice activated...  move, migrate, shoot, bust a cap, &lt;/span&gt;&lt;span class="Apple-style-span" style="  color: rgb(51, 51, 51); line-height: 16px; font-family:arial, helvetica, clean, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;teine (stole that from GI Joe)&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;.  Ok, no voice activation.  &lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;Let's just start randomly right clicking things and see what options appear.  Oh, hey 'Migrate Data'... that's exactly what I want.  In fact, I just realized if I have the source table selected 'Migrate Data' also appears as a button on the toolbar.  Click it, get a message, table XYZ does not exist.  Uhm, yes I know, that's why I want to migrate from MySQL.&lt;/p&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_ljPKsAnuHcY/S2M004DSnmI/AAAAAAAABKc/pVcIilF-sRA/s1600-h/error.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 187px;" src="http://3.bp.blogspot.com/_ljPKsAnuHcY/S2M004DSnmI/AAAAAAAABKc/pVcIilF-sRA/s400/error.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5432243658542980706" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p xmlns=""&gt;Hmmm, what else is on the MySQL database right click menu.  Hey, 'Convert Schema', ok sure, *click*.&lt;/p&gt;&lt;a href="http://2.bp.blogspot.com/_ljPKsAnuHcY/S2MyUgE6r3I/AAAAAAAABKU/DSWnNWjOhs4/s1600-h/rightclick.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 237px; height: 196px;" src="http://2.bp.blogspot.com/_ljPKsAnuHcY/S2MyUgE6r3I/AAAAAAAABKU/DSWnNWjOhs4/s400/rightclick.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5432240903328280434" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Well, something happened.  What happened?  Oh, the SQL Server schema in SSMA now has the tables on the metadata explorer.  But wait, the SQL Server Management Studio doesn't show them.  Refresh, still no, run a query, nope no tables. &lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Gotta be a way to make that happen. Right click again on the SSMA explorer.  Let's try, 'Save to script', sure.  That should work..., then I can open the script in the SQL Server Management Studio and run it on the empty Database.  That must mean that when I do stuff to the meta-data explorer it doesn't actually change the SQL database.  Safe feature but what if I &lt;i&gt;WANT&lt;/i&gt; to push my changes to the SQL database.&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;&lt;/span&gt;&lt;a href="http://3.bp.blogspot.com/_ljPKsAnuHcY/S2NZW2iG9NI/AAAAAAAABKk/NDeXWOxmQ7M/s1600-h/synch.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 241px; height: 160px;" src="http://3.bp.blogspot.com/_ljPKsAnuHcY/S2NZW2iG9NI/AAAAAAAABKk/NDeXWOxmQ7M/s400/synch.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5432283824669521106" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;a href="http://3.bp.blogspot.com/_ljPKsAnuHcY/S2NZW2iG9NI/AAAAAAAABKk/NDeXWOxmQ7M/s1600-h/synch.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Wait..., I see another option I didn't notice before... 'Synchronize Database'.  Let's try that instead of saving to script.  *click*.  Something is happening, .... Hey cool, I like how that works - that actually pushed my changes to the SQL database.&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;Ok, so the empty schema is now on the SQL Server...  back to migrating data.  Let's right click the MySQL Schema again and try that 'Migrate Data' option again.  Lot's of stuff seems to be happening. do dee do de dum do de do .... ok, it's done ... it say's it was successful !!   Ok, run some queries via SSMS just to make sure...&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;&lt;span class="Apple-style-span" style="font-size:small;"&gt;IT WORKED ! MySQL database has been migrated to SQL Server ... HOORAY !&lt;/span&gt;&lt;/p&gt;&lt;p xmlns=""&gt;Despite no documentation, a couple errors, and having to kind of just figure stuff out on my own... that actually wasn't too bad.  I look forward to exploring all the options available under the tools menu.&lt;/p&gt;&lt;/content&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-4899098598850533783?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/4899098598850533783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/01/sql-server-migration-assistant-2008-for.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/4899098598850533783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/4899098598850533783'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/01/sql-server-migration-assistant-2008-for.html' title='SQL Server Migration Assistant 2008 for MySQL'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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://3.bp.blogspot.com/_ljPKsAnuHcY/S2Mp0vKjpYI/AAAAAAAABKM/lCdP0xalnH0/s72-c/clip_image002.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-7322757667606088893</id><published>2010-01-11T08:43:00.001-08:00</published><updated>2010-01-11T09:37:32.424-08:00</updated><title type='text'>SQL Query Optimizer</title><content type='html'>Quite possibly the best explanation of the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;SQL&lt;/span&gt; Query Optimizer I have ever read.  Though I have to disagree with the selectivity of "pretty girls" where city = "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Buenos&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Aires&lt;/span&gt;".  I've never been to Rio but I've been a lot of other places and BA stays pretty darn high on the list.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;http://www.simple-talk.com/sql/t-sql-programming/13-things-you-should-know-about-statistics-and-the-query-optimizer/&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Good job Fabiano for writing this in such a way to keep my interest.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-7322757667606088893?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/7322757667606088893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2010/01/sql-query-optimizer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7322757667606088893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7322757667606088893'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2010/01/sql-query-optimizer.html' title='SQL Query Optimizer'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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-4501041662390804509.post-3051608265017422686</id><published>2009-10-22T14:24:00.000-07:00</published><updated>2009-10-22T14:55:02.330-07:00</updated><title type='text'>PLINQO - Converting a project from LINQ to SQL</title><content type='html'>I am still testing PLINQO and getting ready to start publishing my findings in an in depth post but for now I at least wanted to post some gotcha's and "best practice" I discovered while converting my LINQ to SQL project to a PLINQO project.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;If you are converting an existing project be aware that PLINQO gives you much more control over the naming conventions used and the default settings do not match how LINQ behaves. This isn't a problem if your building a project from scratch but if you are &lt;i&gt;converting&lt;/i&gt; a project like I did it will matter. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The 'table' and 'entity' names are easy enough to fix in code if they change during generation but if the association names do not match, your controls will go crazy when you replace the LINQ dbml with the PLINQO dbml. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://1.bp.blogspot.com/_ljPKsAnuHcY/SuDOpXANJ_I/AAAAAAAABGw/WEt9ftHFiJ0/s320/plinqotemplate.png" style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 64px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5395539563534690290" /&gt;&lt;div&gt;LINQ names it associations using a plural format, if you are converting a project I would configure PLINQO to do the same in the DBML template as shown here at the left.  (As you'll note I also chose to name my tables and entities as 'Preserve' and 'Mixed' for personal preference.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My approach when generating the PLINQO files was to leave the existing LINQ context and files in their own folder while I created the PLINQO contexts and files in another.  I figured this would allow me to test individual forms one at a time and move DataSources manually from one to the other. Once it was done and PLINQO outputs were generated I could compare the results and make sure the entities etc. in the DBML files were the same.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The data context namespace generated by PLINQO is also customizable in the template. In my approach I purposely gave it a different namespace than the original LINQ context. This made generating the PLINQO files easy and non intrusive and didn't break my project with the simple act of generating files.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With both contexts now available I simply went through the DataSources one by one and replaced the LINQ DataSource with the PLINQO DataSource and then checked for errors.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Using a different namespace did cause me to have to change the context declaration in code as well as the BindingSource.DataSource property on a couple top level tables.  Because I was careful to keep the association relationship names the same however everything else switched automatically as soon as the top level BindingSource and datacontext was happy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The only real show-stopping issue I ran into during conversion was that PLINQO does not generate code for User Defined Scalar Functions.  To accomodate the switch to PLINQO I had to write some custom code to take the place of the missing UDFs but it was simple code and easily replaced. (I checked and this was already submitted as a feature/bug request on the PLINQO code site. I added my name to the list of "me toos". I expect it won't be long before PLINQO generates code for functions as LINQ does.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, there you go... these are the steps I used and it worked out great.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I will also mention that I did some preliminary SQL Profiling sessions against my new project and the original LINQ to SQL project and the profiles were virutally identical.  Same number of batch requests, same query text etc.  Performance was basically the same.  Now, I was not surprised by any of this since I haven't really used any of the enhanced PLINQO features which would be the true purpose of switching a project over.  The good news is that the baseline is the same which is what I was hoping for.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Stay tuned as I dig a little deeper.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-3051608265017422686?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/3051608265017422686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2009/10/plinqo-converting-project-from-linq-to.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/3051608265017422686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/3051608265017422686'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2009/10/plinqo-converting-project-from-linq-to.html' title='PLINQO - Converting a project from LINQ to SQL'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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://1.bp.blogspot.com/_ljPKsAnuHcY/SuDOpXANJ_I/AAAAAAAABGw/WEt9ftHFiJ0/s72-c/plinqotemplate.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-1071519596301374052</id><published>2009-10-19T10:14:00.000-07:00</published><updated>2009-10-19T12:00:36.291-07:00</updated><title type='text'>PLINQO</title><content type='html'>&lt;div&gt;While DBA by title and trade I do end up writing code from time to time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;Last week I was working with a Linq to SQL project I had developed over the summer to address a small business need.  I had made some table changes and needed to refresh a couple tables/views.  As I began testing the new tables I started getting foreign key violation errors.  I knew immediately what was wrong. Linq to SQL had replaced my deleteonnull settings when I refreshed the context… time to open the context with the XML editor and put all my settings back by hand (sigh).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This got me thinking critically about Linq to SQL.  I have long since resigned myself to the fact that Microsoft is moving on to other pursuits and leaving Linq to SQL behind.  I have accepted the fact that whatever strengths and weaknesses it has, I will have to deal with them as is if I continued to use L-T-S.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It HAS been awhile though, I decided to check the blogosphere and Microsoft websites to see if any recent news had appeared to give me renewed hope in further development.   Maybe Microsoft was changing their tune.  I knew the “entities” effort so far wasn’t winning Microsoft any friends.  Maybe they’ll develop LINQ further after all… hey, one can hope.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;While I didn’t find any information that Microsoft is going to put focus back on LINQ I did stumble onto a third party approach called PLINQO (from the same folks who bring you CODESMITH).  Now, I was always a big “Price is Right" fan so naming a product PLINQO is a marketing gem (if you’re trying to catch my eye at least).  More importantly however I was excited to see someone out there liked LINQ enough to put effort into furthering its development even though Microsoft is abandoning the effort.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I immediately downloaded the trial version and started playing around.  I have never used CODESMITH but getting up to speed on the product in order to use PLINQO turned out to be no big deal.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PLINQO UNBOXED  – FIRST IMPRESSION:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The biggest project I have used LINQ to SQL on so far is an insurance claim database used by a local insurance CO-OP of about 30 school districts in the Pacific Northwest.  I decided I might as well go big on my first test of PLINQO and see how that LINQ project would behave as a PLINQO project.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In under 15 minutes (45 minutes if you include the time it took to watch the instructional video on implementing PLINQO) I had replaced the data context, entities, and code behinds generated by LINQ with those generated by PLINQO.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;More important than the time used implementing PLINQO, an afternoon of bounds testing and walking through the original user stories and scripts produced no issues whatsoever.  In short, the move from LINQ to PLINQO came off without a hitch.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With that done, I’ll start testing the “enhanced” features of PLINQO.  While the feature list is impressive these are the PLINQO claims that I am most interested in.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Preservation of context changes across data table refresh statements (I hate doing work over, and this frustration led to me originally finding PLINQO)&lt;/li&gt;&lt;li&gt;Batch deletes and updates (batch anything get’s me excited)&lt;/li&gt;&lt;li&gt;Reduction of SQL round trips (I am an SQL Profiler Addict, PLINQO will be watched and my results will be posted)&lt;/li&gt;&lt;li&gt;Change Auditing (if this solves a feature request on my insurance database the folks at PLINQO may have a big ‘ol wet kiss from me in their future)&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you are interested in taking a look at PLINQO you can find it here:  &lt;a href="http://plinqo.com/"&gt;http://plinqo.com&lt;/a&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Documentation here:  &lt;a href="http://plinqo.com/Documentation.ashx"&gt;http://plinqo.com/Documentation.ashx&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Feature requests here:  &lt;a href="http://plinqo.com/Feedback.ashx"&gt;http://plinqo.com/Feedback.ashx&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My next post will report the final findings of my test.  If PLINQO does what it claims it will, the PRICE WILL BE RIGHT.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sorry, I couldn't help myself.  The product is called PLINQO for heaven's sake.  Cut me some slack... &lt;a href="http://plinqo.com/"&gt;PLINQO&lt;/a&gt; / &lt;a href="http://en.wikipedia.org/wiki/Plinko"&gt;PLINKO&lt;/a&gt; ... they are phonetically identical.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-1071519596301374052?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/1071519596301374052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2009/10/plinqo.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/1071519596301374052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/1071519596301374052'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2009/10/plinqo.html' title='PLINQO'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-177339661007104344</id><published>2009-09-08T10:39:00.000-07:00</published><updated>2009-09-08T15:25:14.168-07:00</updated><title type='text'>REORGANIZE - WHAT IT DOESN'T DO</title><content type='html'>&lt;p class="MsoNormal"&gt;Many &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;DBAs&lt;/span&gt; use a level of fragmentation as their guide to deciding when to ‘rebuild’ an index or ‘reorganize’ it.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;For example, they will have on their cheat sheet, “25/75 meaning… up to 25% fragmentation (reorganize), any higher (rebuild)”.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;The numbers vary from pro to pro, some as wide as 80/20 others as close as 60/40.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;They all agree on one thing however.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;There are circumstances when ‘reorganize’ won’t reduce fragmentation levels sufficient to their expectation (or at all).&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Why &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;doesn&lt;/span&gt;’t it?&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;While most &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;DBAs&lt;/span&gt; seem to understand that REORGANIZE won’t always do the trick, there seems to be precious little information floating the web as to why?&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Obviously, for the seasoned &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;DBA&lt;/span&gt; there are several factors at play in the decision to reorganize an index as opposed to other options for tuning index performance.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Not the least of which is how busy the table in question may be and what the related service level agreements (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;SLA&lt;/span&gt;) are.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;But, for the sake of this discussion we’ll just stick to why ALTER INDEX REORGANIZE &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;doesn&lt;/span&gt;’t fix fragmentation as well as we sometimes wish it would.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Physical Structure of an Index and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;FILLFACTOR&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If you are not familiar with the physical makeup of a b-tree index, clustered index, heap etc, a &lt;a href="http://msdn.microsoft.com/en-us/library/ms189051.aspx"&gt;great primer can be found in books online&lt;/a&gt;.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Thinking in terms of the leaf nodes let’s address the concept of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;FILLFACTOR&lt;/span&gt;.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;FILLFACTOR&lt;/span&gt; setting tells &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;SQL&lt;/span&gt; Server the amount of free space to leave in each leaf level node of the index at the time that it’s built. &lt;span style="mso-spacerun:yes"&gt; &lt;/span&gt;If your table is going to be highly &lt;i style="mso-bidi-font-style:normal"&gt;read&lt;/i&gt; intensive you may not want or need much free space.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;The benefit is that each read can get as much data as possible without having the overhead of moving from page to page to get it.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;If your database is more &lt;i style="mso-bidi-font-style:normal"&gt;read/write&lt;/i&gt; balanced you may want a little more free space in each leaf so that there is room for new data without the overhead of splitting pages to make room.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;That’s why the server engineers let us modify &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;FILLFACTOR&lt;/span&gt; because every database is different.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;(If the table is purely &lt;i style="mso-bidi-font-style:normal"&gt;write&lt;/i&gt; intensive it probably &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;shouldn&lt;/span&gt;’t be indexed at all.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Why waste the resources to index a table that rarely gets read.)&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;While &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;FILLFACTOR&lt;/span&gt; should be customized to each scenario, I will go ahead and state that a typical &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;FILLFACTOR&lt;/span&gt; is around 90.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Fragmentation&lt;/p&gt;  &lt;p class="MsoNormal"&gt;There are two types of fragmentation in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;SQL&lt;/span&gt; Server.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;The first is internal fragmentation, or the empty space that is spread across all the pages in the index.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;The more space in each individual page the more heavily fragmented (internally that is) the index is said to be.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Keep in mind that some amount of space may be desirable.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Is your database &lt;i style="mso-bidi-font-style:normal"&gt;read&lt;/i&gt; intensive or more &lt;i style="mso-bidi-font-style:normal"&gt;read/write&lt;/i&gt; balanced?&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Where was the fill factor set when the index was first built?&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;The “fragmentation” in this case may be just where it should be.  Above I said 90 is typical but keep in mind that number varies.  In fact, Mike Hotek states in the Microsoft MCTS 70-431 test prep book that he doesn't consider an index internally fragmented until if falls below 75%.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The other type of fragmentation is external.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;An index has a &lt;i style="mso-bidi-font-style: normal"&gt;logical&lt;/i&gt; order, that’s what makes an index useful after all.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;But, the &lt;i style="mso-bidi-font-style:normal"&gt;physical &lt;/i&gt;order of the pages on the disk may not match the logical order after a lot of normal inserts, updates, deletes, etc.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;That’s because the disk is going to write new pages wherever it first finds room on the media.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;External fragmentation in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;SQL&lt;/span&gt; Server is more like the fragmentation most computer users experience with their personal operating system/file systems.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Unlike internal fragmentation, external fragmentation is never good.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;From a performance standpoint less is always better.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;When the physical order of your pages does not match the logical order of the index you’ll be incurring more overhead than what is theoretically possible in any predictable I/O scenario.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Under the Hood&lt;/p&gt;  &lt;p class="MsoNormal"&gt;With the foundation out of the way, let’s find out what’s really going on during an ALTER INDEX REORGANIZE? &lt;/p&gt;  &lt;p class="MsoNormal"&gt;The behavior of ALTER INDEX REORGANIZE is &lt;i style="mso-bidi-font-style:normal"&gt;nearly&lt;/i&gt; identical to the old &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;DBCC&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;INDEXDEFRAG&lt;/span&gt; from the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;pre&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;SQL&lt;/span&gt; 2005 days.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Microsoft chose wisely in using the term REORGANIZE in the newer statement as opposed to “&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;INDEXDEFRAG&lt;/span&gt;” as was used with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;DBCC&lt;/span&gt;.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Reorganize does the best it can with internal fragmentation by compressing available space at the page level and getting rid of unnecessary pages.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;User locks may keep it from getting rid of all possible space however.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Remember also that REORGANIZE will not compress page space beyond the current &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;FILLFACTOR&lt;/span&gt; setting. &lt;span style="mso-spacerun:yes"&gt; &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The first way in which you may be able to increase the effectiveness of your REORGANIZE is by taking a closer look at your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;FILLFACTOR&lt;/span&gt; strategy.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;This strategy will probably change as a table matures (whether over time or overnight… i.e. think bulk load/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;ETL&lt;/span&gt; scenarios).&lt;/p&gt;  &lt;p class="MsoNormal"&gt;To address external fragmentation REORGANIZE attempts to put the pages in a physical order as closely matched to the logical order as possible.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;This works best under a scenario of light usage and low initial fragmentation.&lt;span style="mso-spacerun:yes"&gt;  The reason is that it will skip any page locked by another process.&lt;span&gt;  &lt;/span&gt;That’s any lock mind you, including a shared lock.  Also, contrary to the popular concept of "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;defrag&lt;/span&gt;" reorganize will not create new pages for swapping purposes as a disk &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;defrag&lt;/span&gt; might do (just a page for page swap).&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="mso-spacerun:yes"&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;As fragmentation grows, so does the number of index pages holding the same amount of actual data.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Single locks may start affecting more pages in turn causing more pages to be skipped by the process.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;In cases of widespread fragmentation and heavy usage &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;REORGANIZE's&lt;/span&gt; ability to help becomes more and more powerless.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Another thing that may keep REORGANIZE from having any apparent effect is if you are dealing with very small indexes with only a few pages.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;As fragmentation percentage is reported as a ratio to total data pages it is not uncommon for small indexes to report very large amounts of fragmentation.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;You’ll find that even REBUILD &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;doesn&lt;/span&gt;’t fix the index in these instances.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Not to worry, the performance affect on these small indexes is nil.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;Kalen&lt;/span&gt; Delaney, who knows her stuff, says &lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2008/02/28/fragmentation-revisited.aspx"&gt;any index with less than 100 pages not worth worrying about&lt;/a&gt;.  She further states even a 1000 pages may not be worth the effort.&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Once again, every scenario is different and only you can figure out what a small or large index is for your organization.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;A reoccurring topic you will find in my posts is make sure your getting good baseline info so you know when performance truly is degrading or improving.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Reducing fragmentation statistics is great, but only if it actually improves the actual performance and reliability of your database.  The better solution of course is to utilize methods to reduce the causes of fragmentation in the first place.  That may be my next post.&lt;/p&gt;&lt;p class="MsoNormal"&gt;If anyone else has insight into the limitations of REORGANIZE by all means post them below.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-177339661007104344?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/177339661007104344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2009/09/reorganize-what-it-doesnt-do.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/177339661007104344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/177339661007104344'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2009/09/reorganize-what-it-doesnt-do.html' title='REORGANIZE - WHAT IT DOESN&apos;T DO'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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-4501041662390804509.post-8610622729289975662</id><published>2009-08-28T15:49:00.001-07:00</published><updated>2009-09-02T12:37:31.062-07:00</updated><title type='text'>What's good depends on what's normal; normal isn't always good</title><content type='html'>&lt;div&gt;Do you ever wonder why an actual number is rarely mentioned with regards to batch requests/sec and articles on performance best practices. That’s because perception is everything, or at least the baseline of that perception is.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In my last post I related how an article by Brad McGehee had made me question my batch requests/sec count. He stated, “Generally speaking, over 1000 batch requests per second indicates a very busy SQL Server, and could mean that if you are not already experiencing a CPU bottleneck, that you may very well soon.”&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My perception of that number was that it seemed low compared to the baseline I had recently taken off a new server. A second look proved that my initial baseline (~3900 batches per second) was still accurate and that all other numbers still appeared healthy. Still, McGehee’s comment reminded me that I was a little surprised at that number initially. But, as the days went by my perception became desensitized and pretty soon that counter statistic was perfectly normal.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Before I go further, let’s define the counter stat ( batch requests/sec ). A batch is one or more individual SQL statements issued to the server in a…. uummm, well, batch. ( &lt;a href="http://msdn.microsoft.com/en-us/library/ms175502.aspx"&gt;more on batches here&lt;/a&gt; )  In SQL 7 and 2000 this counter did not actually count batches, it counted remote procedure calls. A batch however may contain one or more RPC. With the release of SQL 2005 the behavior was changed to more closely reflect the name of the statistic. It started counting actual batches. If a batch contained more than one RPC it would get counted accordingly (only once).  Microsoft undid the change in 2005 SP2 stating simply that the change was less useful then they had anticipated. As of this writing we’re back to the statistic counting RPCs, not batches.  &lt;a href="http://support.microsoft.com/kb/936637"&gt;KB article here&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Obviously, each RPC may have infinite variations of complexity. A single complex RPC may tax the server more than 1000 trivial ones. Batch requests/sec on its own then, isn’t that useful. It only becomes meaningful when applied in one of two ways. The first, as a ratio to another statistic such as recompiles per second, CPU usage, etc. Or, when compared to a known good baseline. It’s a nice way of identifying that a server is a lot more (or less) busy than usual. I suppose it also indicates good network throughput if you have really high numbers with no other side effects but there is probably better ways to identify network throughput. Batch requests would have to be pretty astronomical to come up against the limit of today’s 1Gbs network cards.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But still McGehee had me intrigued so I decided to investigate further. What are all these requests? A few seconds of profiling created a trace that identified 90% of those requests coming from a laserfiche audit service. A couple log files to the vendor and we were informed that it had gone rogue. We killed off the process and suddenly my new baseline is only a couple hundred requests per second with the occasional spike to 3000 (that we identified as a legitimate process related to a different application).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My baseline has just changed drastically; my perception of the count has changed drastically. So McGehee’s number was a decent catalyst for investigation after all. But the fact remains, this information really only does me any good on this one server. When it comes to batch requests/sec what’s “good” depends too much on what’s “normal” for your server. And what’s normal may not necessarily be what’s good.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-8610622729289975662?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/8610622729289975662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2009/08/whats-good-depends-on-whats-normal.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/8610622729289975662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/8610622729289975662'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2009/08/whats-good-depends-on-whats-normal.html' title='What&apos;s good depends on what&apos;s normal; normal isn&apos;t always good'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4501041662390804509.post-7696325365953891031</id><published>2009-08-27T13:19:00.001-07:00</published><updated>2009-08-28T13:45:40.183-07:00</updated><title type='text'>batch requests/sec... que tal?</title><content type='html'>&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;div&gt;Day one:  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p class="MsoNormal"&gt;It is my diligent quest to prepare myself and those I love in everyway possible for the imminent zombie apocalypse. My food storage is secure.  My defense has been carefully selected for efficiency, longevity, and portability.  My family has been trained. The only thing left to address at this point is the proper preparation of my SQL Servers. The return of living breathing humanity will have nothing if it doesn't have it's data!&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;But zombies are not the only thing my servers have to worry about, there are more immediate concerns such as poor application development, reckless ad-hoc queries, unwieldy business intelligence reports to be compiled, SQL injection on our web servers, and will someone please think of the clients. Mine aren't the only DBMS I've sworn to defend.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;This blog will serve as a place to document my issues. Primarily for my own purposes mind you.  I tend to remember things better when I've written them down and analyzed them in an after action report. Call it a mental process I picked up all those years I was knuckle draggin’ with the deputies of &lt;st1:place&gt;&lt;st1:placename&gt;Clark&lt;/st1:placename&gt; &lt;st1:placetype&gt;County&lt;/st1:placetype&gt;&lt;/st1:place&gt;. There is a second reason however. I happen to network with a few other DBAs and from time to time I may experience something that may help someone else... it could happen.  Heaven knows I've been saved a time or two by an obscure blog.  Lastly, I spend a lot more time on the computer than I used to, it's time I do something more career-promoting then adjusting my fantasy baseball roster and studying the draft for the upcoming football season.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;So, put your trays upright and fasten those seatbelts because reading my blog about SQL Server will most likely put you right to sleep.  I would hate for you to fall out on the floor and bruise something.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Now, on to my first topic...&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;I was reading an &lt;a href="http://www.sql-server-performance.com/tips/sql_server_performance_monitor_coutners_p1.aspx"&gt;article this morning by Brad McGehee&lt;/a&gt; regarding performance tuning and it made reference to the PerfMon statistic ( batch requests/sec ). It stated ... and I quote,&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;"To get a feel of how busy SQL Server is, monitor the SQLServer: SQL Statistics: Batch Requests/Sec counter. This counter measures the number of batch requests that SQL Server receives per second, and generally follows in step to how busy your server's CPUs are. Generally speaking, over 1000 batch requests per second indicates a very busy SQL Server, and could mean that if you are not already experiencing a CPU bottleneck, that you may very well soon. Of course, this is a relative number, and the bigger your hardware, the more batch requests per second SQL Server can handle."&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;1000 seemed low to me based on my recent baseline review of my own server.... I took a second and pulled up my standby PerfMon counter template, and sure enough. There my server is... running along with an average of 3900 batch requests per second. Should I worry? CPU usage is hovering around 7%, buffer cache hit ratio is pegged at 100%, recompiles are less than 1% of total batch requests, page life expectancy is good. It seems everything else I'm looking at is healthy. What gives ?&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt;The climactic answer will follow in my next post. But I'll give away a little bit of the plot, batch requests per second on it's own really doesn't mean much. This is even more true when you are comparing the stats from a SQL 2008 instance vs a 2005, or 2000 install (or even different service pack installs for that matter), further it has a lot to do with what your server's focus is and what it's running on. &lt;/o:p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;Still...., turns out 3900 is still crazy high.&lt;/o:p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-7696325365953891031?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/7696325365953891031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2009/08/batch-requestssec-que-tal.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7696325365953891031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7696325365953891031'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2009/08/batch-requestssec-que-tal.html' title='batch requests/sec... que tal?'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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-4501041662390804509.post-7885918799222739032</id><published>2009-04-01T09:12:00.000-07:00</published><updated>2009-10-15T09:30:50.500-07:00</updated><title type='text'>Zombieware Consulting</title><content type='html'>In 1999 I met Sgt Randon Walker of the Clark County Sheriff's Office.  He was the CSI detective with the Major Crimes unit and was in need of a database that would do a better job of tracking evidence.  We hit it off immediately and a lifelong friendship quickly developed as we worked together to create a series of solutions to meet his business needs.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Aside from being the newly hired database guy for the department I had also just graduated the academy and had received a commission as a reserve deputy with the same agency.  In addition to being a friend Sergeant Walker now became my mentor and guide in achieving everything I aspired to be as a law enforcement officer.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the next 10 years we worked together in various roles.  The most important lesson he imparted through this time however was preparation for the imminent zombie apocalypse.  If you're ready for that, he advised, you're ready for anything.  This might be an appropriate time to mention that in addition to being the crime scene detective with major crimes he was also a sniper on the SWAT team.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In 2008 when I left the Sheriff's Office to advance my career in new directions I took the lessons that Sergeant Walker had imparted with me.  Starting my own database consulting service left me with no doubts what it should be called.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4501041662390804509-7885918799222739032?l=zombieware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zombieware.blogspot.com/feeds/7885918799222739032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zombieware.blogspot.com/2009/04/zombieware-consulting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7885918799222739032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4501041662390804509/posts/default/7885918799222739032'/><link rel='alternate' type='text/html' href='http://zombieware.blogspot.com/2009/04/zombieware-consulting.html' title='Zombieware Consulting'/><author><name>Russ Thomas</name><uri>http://www.blogger.com/profile/04800643537113927012</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>
