<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>.NET</title>
        <link>http://www.jasonfollas.com/blog/category/5.aspx</link>
        <description>.NET</description>
        <language>en-US</language>
        <copyright>Jason Follas</copyright>
        <managingEditor>jason@jasonfollas.com</managingEditor>
        <generator>Subtext Version 2.0.0.43</generator>
        <item>
            <title>Upcoming Events</title>
            <link>http://jasonfollas.com/blog/archive/2008/09/25/upcoming-events.aspx</link>
            <description>&lt;p&gt;There are a few events taking place in October that I would like to promote:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a target="_blank" href="http://www.dodn.org"&gt;&lt;font size="4"&gt;Day of .NET in Ann Arbor&lt;/font&gt;&lt;/a&gt;&lt;font size="4"&gt;&lt;br /&gt;
Saturday, October 18, 2008&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img hspace="5" align="left" alt="" src="http://www.dodn.org/AnnArbor/Fall2008/images/AnnArbor2008HBadge.png" /&gt;The fourth Day of .NET in Ann Arbor event will take place on the campus of Washenaw Community College in Ann Arbor (or is it actually Ypsilanti?  I can never tell).  The original conference was a collaboration between &lt;a target="_blank" href="http://www.migang.org"&gt;GANG&lt;/a&gt;, &lt;a target="_blank" href="http://www.aadnd.org"&gt;AADND&lt;/a&gt;, and &lt;a target="_blank" href="http://www.nwnug.com"&gt;NWNUG&lt;/a&gt;.  This year, we have officially added &lt;a target="_blank" href="http://portal.artemis-solutions.com/glugnet/"&gt;GLUG.net&lt;/a&gt; and &lt;a target="_blank" href="http://www.grdotnet.org/"&gt;West Michigan&lt;/a&gt; to the list of groups who are assisting in the organization and promotion.  So, for those of you following along at home, this event is the product of &lt;u&gt;FIVE&lt;/u&gt; regional user groups, and like its predecessors, should be a great day of learning and networking.&lt;/p&gt;
&lt;p&gt;The session list has been posted, and there should be something on the schedule for everyone.  Registration is free, and all that we ask is that if you do sign up, then &lt;u&gt;please show up&lt;/u&gt;.  There's nothing worse than wasting sponsorship dollars by ordering too much food or too many T-Shirts (though, this year, we're going to try to get Pizza back on the menu, so food waste should hopefully be minimized).&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;a target="_blank" href="http://www.dayofdotnet.org/AnnArbor/Fall2008/Sessions.aspx"&gt;http://www.dayofdotnet.org/AnnArbor/Fall2008/Sessions.aspx&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;a target="_blank" href="http://www.nwnug.com/PermaLink,guid,20233af5-bc9f-4bf3-a1b4-5fa94233328b.aspx"&gt;Wally McClure appearing at Northwest Ohio .NET User Group&lt;/a&gt;&lt;br /&gt;
Monday, October 20, 2008&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;img hspace="5" align="left" alt="" src="http://upload.wikimedia.org/wikipedia/en/thumb/6/6c/Troymcclure.png/120px-Troymcclure.png" /&gt;"Hello.  I'm Wally McClure.  You might remember me from my many books published by Wrox Press with my picture on them.  Or, the &lt;a target="_blank" href="http://aspnetpodcast.com/CS11/"&gt;ASP.NET Podcast&lt;/a&gt;, where on the website, you'll find pictures of my books with my pictures on them. Or, the very popular &lt;a target="_blank" href="http://geekswithblogs.net/images/geekswithblogs_net/rowser/WindowsLiveWriter/IhavemoreWallyinmylife_148F8/PIC_0185_thumb.jpg"&gt;T-Shirt with my picture on the back&lt;/a&gt;...."&lt;/p&gt;
&lt;p&gt;I met &lt;a href="http://morewally.com"&gt;Wally&lt;/a&gt; this summer at TechEd Developer in Orlando, where one of the first experiences was being crammed into the back seat of a car between him and &lt;a target="_blank" href="http://www.keithelder.net"&gt;Keith Elder&lt;/a&gt;.  He seemed to take a liking to me, and let's just say that my phone now receives more random text messages than ever before.  :-)  &lt;/p&gt;
&lt;p&gt;In all seriousness, Wally was supposed to have appeared at NWNUG in June, just after TechEd, but had to back out due to work commitments (&lt;a target="_blank" href="http://stevesmithblog.com/"&gt;Steve Smith&lt;/a&gt; ended up filling in for him).  We're thrilled that he was still interested in coming to Toledo, and we were able to arrange an October 20th date (note that this is a Monday, not the regular Tuesday meeting night).&lt;/p&gt;
&lt;p&gt;Watch the NWNUG website for further details about the meeting topic.&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/53.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/09/25/upcoming-events.aspx</guid>
            <pubDate>Thu, 25 Sep 2008 16:50:25 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/53.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/09/25/upcoming-events.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/53.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/53.aspx</trackback:ping>
        </item>
        <item>
            <title>Help!</title>
            <link>http://jasonfollas.com/blog/archive/2008/09/15/help.aspx</link>
            <description>&lt;p&gt;&lt;font face="Arial"&gt;Dear Microsoft,&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;We've been pals for a long time, right?  You put out all of these great technologies, and I help others to use them within their own organization.  We have a good thing going, you and me.&lt;/p&gt;
&lt;p&gt;But, I have a problem.  You see, whenever I press this one special key on my keyboard, mostly by accident due to its proximity to ESC and ~, you give me an excuse to stop working and go get coffee.  This isn't very productive.  I don't always want an excuse to get coffee.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/9/r_helpdialog.png" /&gt;&lt;/p&gt;
&lt;p&gt;Can you please add a Cancel button or something?  Your modal dialog is not very friendly at times.&lt;/p&gt;
&lt;p&gt;BFF,&lt;/p&gt;
&lt;p&gt;-Jason&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/51.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/09/15/help.aspx</guid>
            <pubDate>Mon, 15 Sep 2008 18:24:12 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/51.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/09/15/help.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/51.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/51.aspx</trackback:ping>
        </item>
        <item>
            <title>Announcing Tourniquet</title>
            <link>http://jasonfollas.com/blog/archive/2008/08/18/announcing-tourniquet.aspx</link>
            <description>&lt;p&gt;Have you ever gotten an idea stuck in your head?  One that you start your day thinking about in the shower, and then try as you might, you just can't get rid of it?&lt;/p&gt;
&lt;p&gt;That's what happened to me a few months ago.  Specifically, I started thinking about &lt;a href="http://twitter.com/jfollas"&gt;Twitter&lt;/a&gt;, and the problems that it was experiencing.  At that time, the "Fail Whale" was making very frequent appearances, indicating that Twitter was having problems keeping up with the demands being made on it.  My Tweeps (social networking friends on Twitter), all with short attention spans like myself, began chattering about moving to a more reliable platform.  &lt;/p&gt;
&lt;p&gt;But, in my estimation, Twitter was still the best platform to remain on.  Among other things, it was actually the most "mature" in its class - if you can call something a mere two years old as being mature.&lt;/p&gt;
&lt;h4&gt;So, Jason, what is Tourniquet?&lt;/h4&gt;
&lt;p&gt;&lt;font face="Arial"&gt;After quite a few weeks of thinking about the various problems that I was aware of, I came up with a pretty simple solution.  I needed to bounce some ideas off of a sounding board, so I fired off an email to some of my friends: &lt;a target="_blank" href="http://netcave.org/"&gt;Alan Stevens&lt;/a&gt;, &lt;a target="_blank" href="http://keithelder.net"&gt;Keith Elder&lt;/a&gt;, and &lt;a target="_blank" href="http://www.michaeleatonconsulting.com/"&gt;Micheal Eaton&lt;/a&gt;.  &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The contents of that email still serve as a pretty good overview for my vision, which has been realized as "Tourniquet":&lt;/font&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Think of a multi-faceted approach to fixing Twitter's issues that ultimately concentrates on reducing the number of calls that you make into Twitter itself, as well as provides transparent access to Twitter data during Twitter downtimes:&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;1. A personal Twitter proxy.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is simply an API passthrough service that you host yourself.  The thought process here is that Witty and other clients could be configured as to what server is accessed to execute an API call (i.e., by default, it's &lt;font face="Courier New"&gt;http://www.twitter.com/&lt;/font&gt;, but someone hosting a Twitter proxy would be able to specify something like &lt;font face="Courier New"&gt;http://thisismydomainyo.com/tourniquet/&lt;/font&gt; ).  Aside from the server, there's nothing different about the request or response.  That is, the client might hit &lt;font face="Courier New"&gt;http://thisismydomainyo.com/tourniquet/statuses/friends_timeline.xml &lt;/font&gt;instead of&lt;br /&gt;
&lt;font face="Courier New"&gt;http://www.twitter.com/statuses/friends_timeline.xml&lt;/font&gt;.  &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is not a public/shared service - it would be intended for just the user.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;2. Obfuscation/encryption&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Network Nazis suck, and so do people who brag about having smart phones and data plans.  :-)  There may be other reasons why someone would want the URL obfuscated and the response from Twitter encrypted when transfered between the Twitter Proxy and the client.  But, that's what I'm talking about.  Clients would need to be modified to support encryption/obfuscation before the user can utilize it.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;3. Caching&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;While the Tourniquet proxy is fetching the information from Twitter, it might as well cache it to some form of persistent storage.  This can be used to save some calls into the Twitter API, especially for historical data (which is also useful for when they disable access to historical data during times of heavy demand)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt; &lt;font face="Arial"&gt;4. Store and Forward&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Is Twitter down?  Damn!  But, no worries with Tourniquet!  Your status update is saved until Twitter comes back up.  This is really no different than other store-and-forward services, except you're not giving your twitter credentials to some unknown third party website.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt; &lt;font face="Arial"&gt;5. Automated fetching&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Perhaps Tourniquet can periodically fetch your timeline for you and cache it, either by means of some external triggering or by a timer. Then, when you hit the proxy to check for updates, it's already there (and your current request would likely trigger another fetch just to make sure that it has the latest data)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt; &lt;font face="Arial"&gt;6. Tribe-Net Sharing/Synchronization&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Here's where the service gets interesting: @keithelder and @jfollas follow each other, and both run Tourniquet.  So, both proxies can be configured to be able to sync statuses between each other, hopefully saving some Twitter API hits that count towards your hourly usage. (I'm thinking that Direct Messages can somehow be used to announce Tourniquet endpoints).  If Twitter is down and there are some status updates that are available (but not yet on Twitter), those can be propogated across the cloud via proxy-to-proxy synchronization. Eventually, they'll show up as actual Twitter statuses.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I picture the communication resembling something like this:&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;@jfollas's proxy calls @keithelder's proxy, and announces the highest message ID for each person that @jfollas follows.  @keithelder's proxy returns a list statuses for each of those people that it has cached where the message ID is higher (plus any new/unpublished statuses that are in store-and-forward).  @keithelder's proxy will need to call @jfollas's proxy to reciprocate the process.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Another possibility is to also synchronize a single person, perhaps with the goal of maintaining a cache of the last 100 tweets per person on your follow list.  In this case, @jfollas's proxy will call @keithelder's proxy and list all of the message id's that it has cached for the person.  If @keithelder is also following that person (or otherwise happens to have some tweets cached for the person), then any new messages (or any in-between messages that @jfollas's proxy might have missed) will be supplied in the response.&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That was the original concept.  The name "Tourniquet" came from the same place where all good project names come from: the Thesaurus.  I simply looked for synonyms for the word "bandage", stumbled upon this word, and discovered that it was not already well-known as a software product.&lt;/p&gt;
&lt;h4&gt;Alright, sounds good.  Where is Tourniquet?&lt;/h4&gt;
&lt;p&gt;Tourniquet is not a product, per se.  It's a project, and an open source project at that (MIT license).  You can download the source and do just about anything with it from the project site on Codeplex:&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://codeplex.com/tourniquet"&gt;&lt;img alt="Tourniquet Logo" border="0" src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=tourniquet&amp;amp;DownloadId=41394" /&gt;&lt;br /&gt;
http://codeplex.com/tourniquet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To run Tourniquet, you will need to grab the release from Codeplex, set up a database (i.e., run the create scripts), copy the files from the release to your webserver, and then set up a new web application on your webserver.  If this sounds too complicated, then perhaps you should wait until it's a little more refined before checking it out.  I'm just sayin'...   :-P&lt;/p&gt;
&lt;p&gt;As I wrote the code, I tried to keep in mind that not everyone has a really sweet hosting deal.  Therefore, I targeted what I thought to be the lowest common denominators: ASP.NET 2.0 and SQL Server 2005.  &lt;/p&gt;
&lt;p&gt;Classifying SQL Server as a LCD, though, bothered me, for a lot of "common man" hosting plans do not include access to a database at all.  But, being a SQL Server MVP, I found this to be the quickest way to build the prototype and release the project to Codeplex.  The persistance layer actually uses the Provider model, so my goal is to make alternative providers that do not require SQL Server (i.e., maybe XML on the filesystem, or Amazon SimpleDB, etc).&lt;/p&gt;
&lt;p&gt;The point that I'd like to drive home is that the current codebase is very much a proof-of-concept or prototype, albeit a fully functional one (I've been using it for a few weeks).  People may point at my code and say "Why did you do this like that?  Where are your tests?  This code sucks!" and that's okay.  In its current form, it does most of what I outlined in the email above, so I'm content (working software is the #1 measure of success).&lt;/p&gt;
&lt;p&gt;I encourage anyone who wants to participate in taking this prototype to the next level to join the development team.  Contact me through the site, Codeplex, or Twitter (@jfollas).  I'd be very happy if some enthusiastic people could take on the development of parts of the system and run with it.&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/49.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/08/18/announcing-tourniquet.aspx</guid>
            <pubDate>Mon, 18 Aug 2008 04:16:43 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/49.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/08/18/announcing-tourniquet.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/49.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/49.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2008: Spatial Data, Part 8</title>
            <link>http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx</link>
            <description>&lt;p&gt; &lt;/p&gt;
&lt;p&gt;In this, the eighth part in a series on the new Spatial Data types in SQL Server 2008, I'll step away from the database and do a little spatial coding using .NET.&lt;/p&gt;
&lt;h2&gt;Redistributable .NET Library&lt;/h2&gt;
&lt;p&gt;Up to this point in &lt;a target="_blank" href="http://www.jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;the series&lt;/a&gt;, I have demonstrated a lot of interesting (?) things that you can do with the new Spatial data types (&lt;strong&gt;Geometry&lt;/strong&gt; and &lt;strong&gt;Geography&lt;/strong&gt;) in SQL Server 2008.  You might be thinking, "That's swell, and all, but I wish I could do some of that stuff without needing to be tethered to a database."  Well, you know what?  You can!&lt;/p&gt;
&lt;p&gt;I mentioned in a previous post that the Spatial data types were implemented as SQLCLR User-Defined Types.  I've since been corrected by &lt;a target="_blank" href="http://blogs.msdn.com/isaac"&gt;Isaac Kunen&lt;/a&gt;, who stated that they are more accurately described as System-Defined Types, with the difference being that these are automatically installed and available for use as part of SQL Server 2008, regardless of whether the ENABLE CLR bit has been activated.  Semantics aside, these types are merely classes within a .NET assembly, and Microsoft is making this freely available as part of a Feature Pack for SQL Server (which will be redistributable as part of your stand-alone application, according to Isaac):&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=089A9DAD-E2DF-43E9-9CD8-C06320520B40&amp;amp;displaylang=en"&gt;SQL Server 2008 RC0 Feature Pack Download Page&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(Look for "Microsoft SQL Server System CLR Types," which includes the two Spatial types plus the HierarchyID type.  This link is for RC0, and may not be applicable to future versions as the product is finalized and released.)&lt;/p&gt;
&lt;h2&gt;Builder API&lt;/h2&gt;
&lt;p&gt;A new feature that was included with the first Release Candidate (RC0) is the &lt;a target="_blank" href="http://blogs.msdn.com/isaac/archive/2008/05/30/our-upcoming-builder-api.aspx"&gt;Builder API&lt;/a&gt;.  This is a collection of interfaces and classes that helps you to construct spatial types by specifying one point at a time until all points have been added.&lt;/p&gt;
&lt;p&gt;The Builder API is not only useful for creating new instances of spatial data, but also for consuming existing instances one point at a time (maybe to convert an instance into another format).  Documentation is light at the moment, so I'm still trying to grok exactly how to best utilize it.&lt;/p&gt;
&lt;p&gt;For my first experiment with the API, I obtained some Zip Code Boundary data in ASCII format from the U.S. Census Bureau:&lt;/p&gt;
&lt;p&gt;&lt;a title="http://www.census.gov/geo/www/cob/z52000.html#ascii" href="http://www.census.gov/geo/www/cob/z52000.html#ascii"&gt;http://www.census.gov/geo/www/cob/z52000.html#ascii&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My goal was to parse the data, and then create a new &lt;strong&gt;SqlGeography&lt;/strong&gt; instance for each zip code.  (Note: &lt;strong&gt;SqlGeography&lt;/strong&gt; is the .NET class name that T-SQL refers to simply as &lt;strong&gt;Geography&lt;/strong&gt;).  The &lt;strong&gt;SqlGeographyBuilder&lt;/strong&gt; class proved to be perfect for accomplishing this task.&lt;/p&gt;
&lt;p&gt;At its core, the &lt;strong&gt;SqlGeographyBuilder&lt;/strong&gt; implements the &lt;strong&gt;IGeographySink&lt;/strong&gt; interface.  If you wanted to consume an existing &lt;strong&gt;SqlGeography&lt;/strong&gt; instance, you could implement &lt;strong&gt;IGeographySink&lt;/strong&gt; in your own class, and then invoke the &lt;strong&gt;SqlGeography&lt;/strong&gt;'s Populate() instance method, passing in your object as the parameter.  The Populate() method takes care of calling the appropriate &lt;strong&gt;IGeographySink&lt;/strong&gt; methods within your class.&lt;/p&gt;
&lt;p&gt;In this case, I'm not starting with an existing &lt;strong&gt;SqlGeography&lt;/strong&gt; instance, so my code will need to call the methods of the &lt;strong&gt;SqlGeographyBuilder&lt;/strong&gt; in the correct order:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart8_139B8/IGeographySink_2.png"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="386" alt="IGeographySink" width="416" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart8_139B8/IGeographySink_thumb.png" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;After EndGeography() has been invoked, the new instance is available via the ConstructedGeography property of the &lt;strong&gt;SqlGeographyBuilder&lt;/strong&gt; class.  &lt;/p&gt;
&lt;p&gt;Simple enough, right?  Yeah, I'm still a little lost myself...  But, here's some code to help demonstrate what's going on!&lt;/p&gt;
&lt;p&gt;First, let's look at the ASCII data.  A single zip code's boundary might be defined as:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;      1469      -0.824662148292608E+02       0.413848583827499E+02
      -0.824602851767940E+02       0.413864290595145E+02
      -0.824610630000000E+02       0.413860590000000E+02
      -0.824685900000000E+02       0.413841470000000E+02
      -0.824686034536111E+02       0.413843846804627E+02
      -0.824605990000000E+02       0.413863160000000E+02
      -0.824602851767940E+02       0.413864290595145E+02
END&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The very first line happens to contain an identifier (maps to a second file that lists the actual USPS zip code).  The coordinate listed in the first line is not actually part of the boundary, but rather appears to be the population center of that area.  The actual boundary begins with the second line, and continues until you encounter the "END".  Also, in case you couldn't tell, coordinates in this data are in Longitude-Latitude order.&lt;/p&gt;
&lt;p&gt;Since a Zip Code is a polygon, and since we are working with &lt;strong&gt;SqlGeography&lt;/strong&gt;, we must be aware of ring ordering.  That is, the exterior ring of a polygon must be defined in a counter-clockwise order so that as you "walk the ring", the interior is always to your left.  If you reverse the order, then &lt;strong&gt;SqlGeography&lt;/strong&gt; assumes that you're trying to define a polygon containing the entire world &lt;em&gt;except&lt;/em&gt; for the small area inside of the polygon.&lt;/p&gt;
&lt;p&gt;Well, in this case, the order of the points of the Zip Code boundary is defined in clockwise order... so, we must be aware of this and call into the &lt;strong&gt;SqlGeographyBuilder&lt;/strong&gt; in the opposite order (so the last point defined in the ASCII data is the first point used while building our new instance).  &lt;/p&gt;
&lt;p&gt;To accomplish this, I simply parse the Lat/Long coordinates as "double" types, and then push them onto a stack.  Then, I pop the stack and call into the Builder API with each point.  At the end, I obtain the new &lt;strong&gt;SqlGeography&lt;/strong&gt; instance from the ConstructedGeography property.  &lt;/p&gt;
&lt;p&gt;(Note: This is demonstrative code - some things should probably be cleaned up/refactored/error handled... You have been warned)&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; SqlGeography ParseAsGeography(&lt;span class="kwrd"&gt;string&lt;/span&gt; zipcode_points)
{
    StringReader sr = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringReader(zipcode_points);
    &lt;span class="kwrd"&gt;string&lt;/span&gt; line = sr.ReadLine();

    Stack&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;[]&amp;gt; Points = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stack&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;[]&amp;gt;();

    &lt;span class="kwrd"&gt;while&lt;/span&gt; (line != &lt;span class="kwrd"&gt;null&lt;/span&gt;  &amp;amp;&amp;amp; line != &lt;span class="str"&gt;"END"&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (line != String.Empty)
        {
            Points.Push(ParseLatLngValues(line));
        }

        line = sr.ReadLine();
    }

    &lt;span class="kwrd"&gt;return&lt;/span&gt; CreateGeography(Points);
}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;[] ParseLatLngValues(&lt;span class="kwrd"&gt;string&lt;/span&gt; line)
{
    &lt;span class="rem"&gt;//      -0.838170700000000E+02       0.409367390000000E+02&lt;/span&gt;

    &lt;span class="kwrd"&gt;double&lt;/span&gt;[] ret = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;[2];

    &lt;span class="kwrd"&gt;string&lt;/span&gt; lng = System.Text.RegularExpressions.Regex&lt;br /&gt;                            .Matches(line, &lt;span class="str"&gt;"\\S+"&lt;/span&gt;)[0].Value;
    &lt;span class="kwrd"&gt;string&lt;/span&gt; lat = System.Text.RegularExpressions.Regex&lt;br /&gt;                            .Matches(line, &lt;span class="str"&gt;"\\S+"&lt;/span&gt;)[1].Value;

    &lt;span class="kwrd"&gt;double&lt;/span&gt;.TryParse(lat, &lt;span class="kwrd"&gt;out&lt;/span&gt; ret[0]);
    &lt;span class="kwrd"&gt;double&lt;/span&gt;.TryParse(lng, &lt;span class="kwrd"&gt;out&lt;/span&gt; ret[1]);

    &lt;span class="kwrd"&gt;return&lt;/span&gt; ret;
}&lt;/pre&gt;
&lt;p&gt;&lt;a title="http://www.microsoft.com/downloads/details.aspx?FamilyId=089A9DAD-E2DF-43E9-9CD8-C06320520B40&amp;amp;displaylang=en" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=089A9DAD-E2DF-43E9-9CD8-C06320520B40&amp;amp;displaylang=en"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; SqlGeography CreateGeography(Stack&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;[]&amp;gt; points)
{
    SqlGeographyBuilder builder = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlGeographyBuilder();
    builder.SetSrid(4326);
    builder.BeginGeography(OpenGisGeographyType.Polygon);

    &lt;span class="kwrd"&gt;double&lt;/span&gt;[] point = points.Pop();

    builder.BeginFigure(point[0], point[1]);

    &lt;span class="kwrd"&gt;while&lt;/span&gt; (points.Count &amp;gt; 0)
    {
        point = points.Pop();
        builder.AddLine(point[0], point[1]);
    }

    builder.EndFigure();
    builder.EndGeography();

    &lt;span class="kwrd"&gt;return&lt;/span&gt; builder.ConstructedGeography;
}&lt;/pre&gt;
&lt;p&gt;&lt;a href="http://www.jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;SQL Server 2008: Spatial Data, Part 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;SQL Server 2008: Spatial Data, Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx"&gt;SQL Server 2008: Spatial Data, Part 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx"&gt;SQL Server 2008: Spatial Data, Part 4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx"&gt;SQL Server 2008: Spatial Data, Part 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx"&gt;SQL Server 2008: Spatial Data, Part 6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx"&gt;SQL Server 2008: Spatial Data, Part 7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f06%2f23%2fsql-server-2008-spatial-data-part-8.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f06%2f23%2fsql-server-2008-spatial-data-part-8.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/46.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx</guid>
            <pubDate>Tue, 24 Jun 2008 02:18:47 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/46.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx#feedback</comments>
            <slash:comments>9</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/46.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/46.aspx</trackback:ping>
        </item>
        <item>
            <title>Coding in SQL Server: An Evolution</title>
            <link>http://jasonfollas.com/blog/archive/2008/06/19/coding-in-sql-server-an-evolution.aspx</link>
            <description>&lt;p&gt;Tuesday at the &lt;a target="_blank" href="http://www.nwnug.com/PermaLink,guid,95b33c73-aca9-4f3f-842e-3eec9158795b.aspx"&gt;NWNUG&lt;/a&gt; meeting, &lt;a target="_blank" href="http://aspadvice.com/blogs/ssmith/"&gt;Steven Smith&lt;/a&gt; spoke on various ways to squeeze performance out of your ASP.NET applications.  This was a fantastic talk, and gave me plenty to think about (since ASP.NET is not my forte, I only consider myself to have an intermediate skillset on this topic).&lt;/p&gt;
&lt;p&gt;One suggestion that he made involved caching database writes.  That is, instead of immediately writing logging-type information to the database for every request, which is a relatively expensive operation considering the small payload size, that you could accumulate them in a short-term cache, and then perform the write operation periodically.  Fewer database calls = faster performance.&lt;/p&gt;
&lt;p&gt;In his example, he spoke of his advertisement server that might serve many impressions per second, but he doesn't want each impression to incur an expensive database write.  So, he keeps track of the activity locally, and then persists to the database every 5 seconds using a single database call containing multiple data points.&lt;/p&gt;
&lt;p&gt;The code that Steve demonstrated utilized XML to contain the data within a single block of text (read: can be passed in as a single parameter to a stored procedure):&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ROOT&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Activity&lt;/span&gt; &lt;span class="attr"&gt;customerId&lt;/span&gt;&lt;span class="kwrd"&gt;="ALFKI"&lt;/span&gt; &lt;span class="attr"&gt;viewCount&lt;/span&gt;&lt;span class="kwrd"&gt;="5"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Activity&lt;/span&gt; &lt;span class="attr"&gt;customerId&lt;/span&gt;&lt;span class="kwrd"&gt;="ANATR"&lt;/span&gt; &lt;span class="attr"&gt;viewCount&lt;/span&gt;&lt;span class="kwrd"&gt;="7"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ROOT&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now, consuming XML from T-SQL is an area that I know very well, so I cringed a little bit when Steve showed the actual stored procedure code itself:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; dbo.BulkLogCustomerViews
  @@doc text &lt;span class="rem"&gt;-- XML Doc...&lt;/span&gt;
&lt;span class="kwrd"&gt;AS&lt;/span&gt;

&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @idoc   &lt;span class="kwrd"&gt;int&lt;/span&gt;

&lt;span class="rem"&gt;-- Create an internal representation (virtual table) of &lt;br /&gt;   the XML document...&lt;/span&gt;
&lt;span class="kwrd"&gt;EXEC&lt;/span&gt; sp_xml_preparedocument @idoc &lt;span class="kwrd"&gt;OUTPUT&lt;/span&gt;, @@doc

&lt;span class="rem"&gt;-- Perform UPDATES&lt;/span&gt;
&lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; TopCustomerLog
&lt;span class="kwrd"&gt;SET&lt;/span&gt; TopCustomerLog.ViewCount = TopCustomerLog.ViewCount &lt;br /&gt;    + ox2.viewCount
&lt;span class="kwrd"&gt;FROM&lt;/span&gt; &lt;span class="kwrd"&gt;OPENXML&lt;/span&gt; (@idoc, &lt;span class="str"&gt;'/ROOT/Activity'&lt;/span&gt;,1)
          &lt;span class="kwrd"&gt;WITH&lt;/span&gt; ( [customerId]  &lt;span class="kwrd"&gt;NCHAR&lt;/span&gt;(5)
        , viewCount &lt;span class="kwrd"&gt;int&lt;/span&gt;
        ) ox2
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; TopCustomerLog.[customerId] = ox2.[customerId]
 
&lt;span class="rem"&gt;-- Perform INSERTS&lt;/span&gt;
INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; TopCustomerLog
     ( CustomerID
     , ViewCount
     )
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [customerId]
     , viewCount
  &lt;span class="kwrd"&gt;FROM&lt;/span&gt; &lt;span class="kwrd"&gt;OPENXML&lt;/span&gt; (@idoc, &lt;span class="str"&gt;'/ROOT/Activity'&lt;/span&gt;,1)
          &lt;span class="kwrd"&gt;WITH&lt;/span&gt; ( customerId  &lt;span class="kwrd"&gt;NCHAR&lt;/span&gt;(5)
        , viewCount  &lt;span class="kwrd"&gt;int&lt;/span&gt;
        ) ox
  &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;EXISTS&lt;/span&gt; 
(&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; customerId &lt;span class="kwrd"&gt;FROM&lt;/span&gt; TopCustomerLog 
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; TopCustomerLog.customerId = ox.customerId)

&lt;span class="rem"&gt;-- Remove the 'virtual table' now...&lt;/span&gt;
&lt;span class="kwrd"&gt;EXEC&lt;/span&gt; sp_xml_removedocument @idoc&lt;/pre&gt;
&lt;p&gt;&lt;span class="kwrd"&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="kwrd"&gt;Now, to Steve's credit, this code works just fine, and can probably be used as-is on all versions of SQL Server from 7.0 through 2008.  But, since we really don't write ASP applications consisting entirely of Response.Write any longer, I'd like to see Steve update his demo to use more modern techniques on the database as well.  ;-)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="kwrd"&gt;The first thing that he could do is update the procedure to utilize the XML data type that was first introduced in SQL Server 2005.  This would simplify the code a little bit, and would get rid of the dependency on the COM-based MSXML.dll, which the sp_xml_preparedocument and OPENXML() uses.&lt;/span&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; dbo.BulkLogCustomerViews
  @doc xml
&lt;span class="kwrd"&gt;AS&lt;/span&gt;

&lt;span class="rem"&gt;-- Perform UPDATES&lt;/span&gt; &lt;br /&gt;&lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; TopCustomerLog
&lt;span class="kwrd"&gt;SET&lt;/span&gt;    TopCustomerLog.ViewCount = TopCustomerLog.ViewCount &lt;br /&gt;       + ox2.viewCount
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;   (
       &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; T.activity.&lt;span class="kwrd"&gt;value&lt;/span&gt;(&lt;span class="str"&gt;'@customerId'&lt;/span&gt;, &lt;span class="str"&gt;'nchar(5)'&lt;/span&gt;) &lt;br /&gt;              as CustomerID, 
              T.activity.&lt;span class="kwrd"&gt;value&lt;/span&gt;(&lt;span class="str"&gt;'@viewCount'&lt;/span&gt;, &lt;span class="str"&gt;'int'&lt;/span&gt;) viewCount
       &lt;span class="kwrd"&gt;FROM&lt;/span&gt;   @doc.nodes(&lt;span class="str"&gt;'/ROOT/Activity'&lt;/span&gt;) &lt;span class="kwrd"&gt;as&lt;/span&gt; T(activity)
       ) ox2
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;  TopCustomerLog.[customerId] = ox2.[customerId]
 
&lt;span class="rem"&gt;-- Perform INSERTS&lt;/span&gt;
INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; TopCustomerLog
     ( CustomerID
     , ViewCount
     )
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [customerId]
     , viewCount
&lt;span class="kwrd"&gt;FROM&lt;/span&gt; (
       &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; T.activity.&lt;span class="kwrd"&gt;value&lt;/span&gt;(&lt;span class="str"&gt;'@customerId'&lt;/span&gt;, &lt;span class="str"&gt;'nchar(5)'&lt;/span&gt;) &lt;br /&gt;              as CustomerID, 
              T.activity.&lt;span class="kwrd"&gt;value&lt;/span&gt;(&lt;span class="str"&gt;'@viewCount'&lt;/span&gt;, &lt;span class="str"&gt;'int'&lt;/span&gt;) viewCount
       &lt;span class="kwrd"&gt;FROM&lt;/span&gt;   @doc.nodes(&lt;span class="str"&gt;'/ROOT/Activity'&lt;/span&gt;) &lt;span class="kwrd"&gt;as&lt;/span&gt; T(activity)
       ) ox
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;EXISTS&lt;/span&gt; (
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; customerId &lt;span class="kwrd"&gt;FROM&lt;/span&gt; TopCustomerLog 
    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; TopCustomerLog.customerId = ox.customerId )&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
Note that the XML data type in SQL Server doesn't need to be a well-formed document.  In this case, Steve could just pass in series of "Activity" elements (no "ROOT" element would be required by SQL Server, so he would also be able to simplify the .NET code that actually creates the XML string):&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Activity&lt;/span&gt; &lt;span class="attr"&gt;customerId&lt;/span&gt;&lt;span class="kwrd"&gt;="ALFKI"&lt;/span&gt; &lt;span class="attr"&gt;viewCount&lt;/span&gt;&lt;span class="kwrd"&gt;="5"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Activity&lt;/span&gt; &lt;span class="attr"&gt;customerId&lt;/span&gt;&lt;span class="kwrd"&gt;="ANATR"&lt;/span&gt; &lt;span class="attr"&gt;viewCount&lt;/span&gt;&lt;span class="kwrd"&gt;="7"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Consequently, the XPath (XQuery, actually) within the nodes() method of the stored procedure code would need to change as well: &lt;/p&gt;
&lt;pre class="csharpcode"&gt;@doc.nodes(&lt;span class="str"&gt;'Activity'&lt;/span&gt;) &lt;span class="kwrd"&gt;as&lt;/span&gt; T(activity)&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
But, we can kick this up a notch and use some SQL Server 2008 features as well. First, there's new "Upsert" capabilities (MERGE statement) that tries to simplify what Steve does with the UPDATE followed by INSERT:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; dbo.BulkLogCustomerViews
  @doc xml
&lt;span class="kwrd"&gt;AS&lt;/span&gt;

MERGE TopCustomerLog &lt;span class="kwrd"&gt;AS&lt;/span&gt; target
&lt;span class="kwrd"&gt;USING&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; T.activity.&lt;span class="kwrd"&gt;value&lt;/span&gt;(&lt;span class="str"&gt;'@customerId'&lt;/span&gt;, &lt;span class="str"&gt;'nchar(5)'&lt;/span&gt;) 
              &lt;span class="kwrd"&gt;as&lt;/span&gt; CustomerID, 
              T.activity.&lt;span class="kwrd"&gt;value&lt;/span&gt;(&lt;span class="str"&gt;'@viewCount'&lt;/span&gt;, &lt;span class="str"&gt;'int'&lt;/span&gt;) &lt;span class="kwrd"&gt;as&lt;/span&gt; viewCount
       &lt;span class="kwrd"&gt;FROM&lt;/span&gt;   @doc.nodes(&lt;span class="str"&gt;'Activity'&lt;/span&gt;) &lt;span class="kwrd"&gt;as&lt;/span&gt; T(activity)) &lt;span class="kwrd"&gt;AS&lt;/span&gt; source 
&lt;span class="kwrd"&gt;ON&lt;/span&gt;    (target.CustomerID = source.CustomerID)
&lt;span class="kwrd"&gt;WHEN&lt;/span&gt;  MATCHED 
      &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; &lt;span class="kwrd"&gt;SET&lt;/span&gt; target.ViewCount = target.ViewCount + source.viewCount
&lt;span class="kwrd"&gt;WHEN&lt;/span&gt;  &lt;span class="kwrd"&gt;NOT&lt;/span&gt; MATCHED
      &lt;span class="kwrd"&gt;THEN&lt;/span&gt; INSERT (CustomerID, ViewCount)
      &lt;span class="kwrd"&gt;VALUES&lt;/span&gt; (source.CustomerID, source.viewCount);&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;One more thing that could be done to further simplify this T-SQL is to use a Table-valued Parameter instead of the XML.  This would allow Steve to pass a fully populated table of data into the stored procedure and consume it directly by the MERGE statement.&lt;/p&gt;
&lt;p&gt;The first step is to create a T-SQL type that defines the table structure of the parameter (this is a one-time operation, unless the table structure changes):&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; TYPE CustomerViewType &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; 
( 
    CustomerID &lt;span class="kwrd"&gt;nchar&lt;/span&gt;(5) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    ViewCount &lt;span class="kwrd"&gt;int&lt;/span&gt; &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;
);&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now, a parameter can be defined of this type, and used just like any other table-value variable:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; dbo.BulkLogCustomerViews
  @views CustomerViewType READONLY
&lt;span class="kwrd"&gt;AS&lt;/span&gt;

MERGE TopCustomerLog &lt;span class="kwrd"&gt;AS&lt;/span&gt; target
&lt;span class="kwrd"&gt;USING&lt;/span&gt; @views &lt;span class="kwrd"&gt;AS&lt;/span&gt; source 
&lt;span class="kwrd"&gt;ON&lt;/span&gt;    (target.CustomerID = source.CustomerID)
&lt;span class="kwrd"&gt;WHEN&lt;/span&gt;  MATCHED 
      &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; &lt;span class="kwrd"&gt;SET&lt;/span&gt; target.ViewCount = target.ViewCount &lt;br /&gt;                      + source.viewCount
&lt;span class="kwrd"&gt;WHEN&lt;/span&gt;  &lt;span class="kwrd"&gt;NOT&lt;/span&gt; MATCHED
      &lt;span class="kwrd"&gt;THEN&lt;/span&gt; INSERT (CustomerID, ViewCount)
      &lt;span class="kwrd"&gt;VALUES&lt;/span&gt; (source.CustomerID, source.viewCount);&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;On the ADO.NET side, the table-valued parameter could be represented as a DataTable object (other options also exist), and can be assigned directly as the value of the stored procedure's parameter object:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// Create a data table, and provide its structure&lt;/span&gt;
DataTable customerViews = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataTable();
customerViews.Columns.Add(&lt;span class="str"&gt;"CustomerID"&lt;/span&gt;, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;));
customerViews.Columns.Add(&lt;span class="str"&gt;"ViewCount"&lt;/span&gt;, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;int&lt;/span&gt;));

&lt;span class="rem"&gt;// Fill with rows&lt;/span&gt;
customerViews.Rows.Add(&lt;span class="str"&gt;"ALFKI"&lt;/span&gt;, 5);
customerViews.Rows.Add(&lt;span class="str"&gt;"ANATR"&lt;/span&gt;, 7);

&lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection conn = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection(&lt;span class="str"&gt;"..."&lt;/span&gt;))
{
  SqlCommand cmd = conn.CreateCommand();
  cmd.CommandType = System.Data.CommandType.StoredProcedure;
  cmd.CommandText = &lt;span class="str"&gt;"dbo.BulkLogCustomerViews"&lt;/span&gt;;

  SqlParameter param &lt;br /&gt;        = cmd.Parameters.AddWithValue(&lt;span class="str"&gt;"@views"&lt;/span&gt;, customerViews);

  conn.Open();

  cmd.ExecuteNonQuery();
}&lt;/pre&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/45.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/06/19/coding-in-sql-server-an-evolution.aspx</guid>
            <pubDate>Thu, 19 Jun 2008 20:50:36 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/45.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/06/19/coding-in-sql-server-an-evolution.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/45.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/45.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2008: Spatial Data, Part 7</title>
            <link>http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx</link>
            <description>&lt;p&gt;The &lt;a target="_blank" href="http://www.opengeospatial.org"&gt;Open Geospatial Consortium&lt;/a&gt;'s &lt;a target="_blank" href="http://www.opengeospatial.org/standards/sfa"&gt;Simple Features specification&lt;/a&gt;, which SQL Server 2008's &lt;strong&gt;Geometry&lt;/strong&gt; data type is based upon, defines standards for working with spatial data using a flat-earth (projected planar) model.  Ironically, these standards don't exactly cover the intricacies of using an ellipsoidal model, which is needed to "accurately" represent the world that we live in.  In other words, the OGC standards define how to work with paper maps of the world, but not globes.&lt;/p&gt;
&lt;p&gt;Fortunately, the SQL Server team recognized that that the &lt;strong&gt;Geometry&lt;/strong&gt; type is inadequate for a lot of scenarios, and implemented a second data type just for representing geospatial data using a true ellipsoidal model: &lt;strong&gt;Geography&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this, the seventh part of a series about the SQL Server Spatial Data Type, I'll examine some of the key differences between the &lt;strong&gt;Geometry&lt;/strong&gt; and the &lt;strong&gt;Geography&lt;/strong&gt; type that developers should be aware of.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Latitude and Longitude&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
Locations on a flat model are defined in terms of X and Y.  There exists some point known as the Origin where X and Y are both zero.  From there, it is defined that values of X will increase (or decrease, in the case of negatve numbers) if you move horizontally away from the Origin.  Likewise, the values of Y will increase if you move vertically away from the Origin.  &lt;/p&gt;
&lt;p&gt;By convention, both X and Y will grow to infinity, so flat models do not "wrap around" and start approaching the Origin again if you go too far in one direction.  Usually, a coordinate system will be based on some underlying representation of the real-world, so coordinates that are beyond the defined boundaries of that map are logically undefined.&lt;/p&gt;
&lt;p&gt;By contrast, though, an ellipsoidal model &lt;em&gt;does&lt;/em&gt; wrap around.  If you started at a point in the middle and kept traveling in a straight line to the right, you will eventually return to that starting point.  &lt;/p&gt;
&lt;p&gt;So, it turns out not to be very practical to define points on a ball using X and Y.  Instead, points are defined using angles.  Longitude is the horizontal angle (how far East or West from a &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Prime_meridian"&gt;Prime Meridian&lt;/a&gt;) and ranges from -180 degrees to 180 degrees (with -180 and 180 being the same).  Latitude is the vertical angle (how far North or South from the Equator) and ranges from -90 degrees to 90 degrees (with -90 representing the South Pole and 90 representing the North Pole).&lt;/p&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="240" alt="latlon" width="229" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/latlon_3.jpg" /&gt; &lt;/p&gt;
&lt;p&gt;In terms of the &lt;strong&gt;Geography&lt;/strong&gt; data type, just be aware that there is no X and Y.  Instead, you work with Long and Lat.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: All of the SQL Server 2008 CTPs to date that include Spatial support, including the most recent February 2008 version, use Lat-Long ordering within WKT.  This was a design decision based on the fact that the OGC standard did not already define parameter ordering for angular coordinates.  Starting with the first Release Candidate, however, these parameters will be swapped to use Long-Lat ordering.  Doing so will align SQL Server's spatial support with other platforms that have already implemented Long-Lat ordering.  Note also that that this is aligned with the concepts of X and Y, which by convention lists the X value first.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Straight Lines&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
The shortest distance between two points is a straight line.  But, a straight line on a flat-earth model is far different than a straight line on an ellipsoidal model.  To demonstrate, consider the shortest path from Redmond, WA, USA to Cambridge, England, UK: &lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_1_2.png"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="290" alt="s7_1" width="380" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_1_thumb.png" /&gt;&lt;/a&gt;  &lt;br /&gt;
On this planar projection, it certainly looks like the shortest path.  Even when examined on a 3D model, it looks correct: &lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_2_2.png"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="274" alt="s7_2" width="364" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_2_thumb.png" /&gt;&lt;/a&gt; &lt;br /&gt;
But, if the camera is moved towards the North Pole, then the error becomes apparent:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_3_2.png"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="274" alt="s7_3" width="364" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_3_thumb.png" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;In the ellipsoidal model, the shortest path between the points is not the red line, which roughly parallels the lines of Latitude, but rather the black arrow!  Converted back to a planar projection, this actual shortest path appears curved:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_4_2.png"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="290" alt="s7_4" width="380" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/s7_4_thumb.png" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;em&gt;(in this view, the black curve was [hastily] plotted by hand)&lt;/em&gt; &lt;br /&gt;
&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;h2&gt;Instance Methods&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
The following slide shows in all of the instance methods that have been implemented for the &lt;strong&gt;Geography&lt;/strong&gt; type as of the February 2008 CTP.  For comparison, instance methods from the &lt;strong&gt;Geometry&lt;/strong&gt; type that do not exist in the &lt;strong&gt;Geography&lt;/strong&gt; type are shown in gray.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/GeographyMethods_2.png"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="260" alt="GeographyMethods" width="340" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart7_128A3/GeographyMethods_thumb.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It may be impossible to define some of these equivalent methods for &lt;strong&gt;Geography&lt;/strong&gt;, simply because the rules are different.  For instance, if you define a set of points that make up a Polygon, what is considered to be the interior and exterior of that shape?  Since the world coordinates wrap around in an ellipsoidal model, you might be intending to represent a shape whose interior is the entire world except for the small portion.  There is simply no way to convey your intent using the methods as described by the OGC standard.&lt;/p&gt;
&lt;p&gt;In an attempt to prevent this particular scenario, the SQL Server team has imposed a limit on the size of a &lt;strong&gt;Geography&lt;/strong&gt; in the February 2008 CTP: you cannot define a &lt;strong&gt;Geography&lt;/strong&gt; that is larger than a hemisphere.   &lt;/p&gt;
&lt;p&gt;There may very well be logical solutions for working around some of the issues that prevented the SQL team from implementing all of &lt;strong&gt;Geometry's&lt;/strong&gt; methods in the &lt;strong&gt;Geography&lt;/strong&gt; type.  However, in this case, Microsoft appears to be waiting for the OGC to define certain rules as part of a standard rather than coming up with their own assumptions, which could be invalidated later by the standards group going in a different direction.&lt;/p&gt;
&lt;p&gt;More on the &lt;strong&gt;Geography&lt;/strong&gt; type later!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;SQL Server 2008: Spatial Data, Part 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;SQL Server 2008: Spatial Data, Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx"&gt;SQL Server 2008: Spatial Data, Part 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx"&gt;SQL Server 2008: Spatial Data, Part 4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx"&gt;SQL Server 2008: Spatial Data, Part 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx"&gt;SQL Server 2008: Spatial Data, Part 6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx"&gt;(next part) SQL Server 2008: Spatial Data, Part 8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f05%2f16%2fsql-server-2008-spatial-data-part-7.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f05%2f16%2fsql-server-2008-spatial-data-part-7.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/42.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx</guid>
            <pubDate>Sat, 17 May 2008 02:53:41 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/42.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/42.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/42.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2008: Spatial Data, Part 6</title>
            <link>http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx</link>
            <description>&lt;p&gt; &lt;/p&gt;
&lt;p&gt;In the &lt;a target="_blank" href="http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx"&gt;Part 4&lt;/a&gt; and &lt;a target="_blank" href="http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx"&gt;Part 5&lt;/a&gt; of the series, I demonstrated some instance methods of the &lt;strong&gt;Geometry&lt;/strong&gt; type that returned a new &lt;strong&gt;Geometry&lt;/strong&gt; based on existing instances.  In this part, I will concentrate on instance methods and properties of the &lt;strong&gt;Geometry&lt;/strong&gt; type that return scalar values and Points. &lt;br /&gt;
&lt;/p&gt;
&lt;h2&gt;STArea, STLength&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
Typically, your spatial data will represent something from the real world.  A LineString may be the collection of points gathered from a GPS device, and together they may represent the path that you took from your home to the office.  A Polygon may be the collection of points around the boundary of governmental territory, like a county or a parish within your state.&lt;/p&gt;
&lt;p&gt;In both of these cases, the time will come when you will want to know the length of the LineString (or length of the perimeter of the Polygon) and the area within the Polygon.  OGC standard method &lt;font face="monospace"&gt;STArea()&lt;/font&gt; returns a float indicating the area of the instance in square units (or 0, if the instance is not a Polygon and does not have area).  &lt;font face="monospace"&gt;STLength()&lt;/font&gt; returns a float indicating the length of the instance in units (or 0, if the instance is a Point and does not have length).  &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g GEOMETRY = &lt;span class="str"&gt;'POLYGON((10 10, 10 40, 40 40, 10 10))'&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STArea(), @g.STLength()

Results:

Area       Length&lt;br /&gt;450        102.426406871193&lt;/pre&gt;
&lt;p&gt; &lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="52" alt="Spatial_6_1" width="57" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A265/Spatial_6_1_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STCentroid&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
Thinking back to Mr. Bollenbacher's 10th Grade Geometry class, we had to use a compass and straight edge to construct lines bisecting the angles of polygons (primarily triangles).  The point where the angle bisectors met was the exact center, or &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Centroid"&gt;centroid&lt;/a&gt;, of the shape.  Centroids are important because any line that passes through a centroid will divide the Polygon into two parts of equal area.  It should be noted that a Centroid may not actually be on the surface of a Polygon.&lt;/p&gt;
&lt;p&gt;The OGC standard method &lt;font face="monospace"&gt;STCentroid()&lt;/font&gt; returns a Point indicating the centroid of the shape.  If the instance is not a Polygon (or MultiPolygon), then NULL will be returned.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g GEOMETRY = &lt;span class="str"&gt;'POLYGON((10 10, 10 40, 40 40, 10 10))'&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STCentroid().ToString()

Results:

POINT (20 30)&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="52" alt="Spatial_6_2" width="57" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A265/Spatial_6_2_3.png" /&gt;  &lt;br /&gt;
&lt;em&gt;Note: SpatialViewer displays an individual point as an X. &lt;br /&gt;
&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;STWithin, STContains&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
Two OGC standard methods returns a 1 or 0 indicating whether all of the points of one instance exist entirely inside of another instance.  &lt;font face="monospace"&gt;STWithin()&lt;/font&gt; tests whether the base instance is inside of the parameter instance, while &lt;font face="monospace"&gt;STContains()&lt;/font&gt; tests whether the parameter instance is inside of the base instance.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g geometry = &lt;span class="str"&gt;'POLYGON ((10 10, 13 30, 30 30, 30 15, &lt;br /&gt;                                 10 10))'&lt;/span&gt;
&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @h geometry = &lt;span class="str"&gt;'LINESTRING (16 16, 16 24, 25 18)'&lt;br /&gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STContains(@h), @g.STWithin(@h)&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @h.STContains(@g), @h.STWithin(@g) &lt;br /&gt;
Results:

1     0&lt;br /&gt;&lt;br /&gt;0     1&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="41" alt="Spatial_6_3" width="51" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A265/Spatial_6_3_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;ST is {something}?&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
There are a number of OGC standard methods to check whether a given instance meets certain specifications: STIsClosed, STIsEmpty, STIsRing, STIsSimple, STIsValid&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CLOSED:&lt;/strong&gt; An instance is considered to be closed if the start point is the same as the end point.  By definition, a Polygon has to be closed, and a Point is not closed.  That really only leaves LineString.  For a collection of objects to be considered closed, all of its members must be closed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EMPTY:&lt;/strong&gt; A &lt;strong&gt;Geometry&lt;/strong&gt; can be initialized in a special way as to not contain any points.  In SQL terms, this is sort of like having a NULL value, except it really is an instantiated object.  For example, LINESTRING EMPTY is a valid LineString, but it has no points.  Another humorous example is POINT EMPTY, which initializes to a Point without a Point....  so it's kind of Pointless, right?  (thank you, I'm here all week, tip your waitress).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RING:&lt;/strong&gt; An instance is considered to be a ring if it is both Closed and Simple.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SIMPLE:&lt;/strong&gt; An instance is considered to be simple if it does not cross over itself or otherwise touch itself.  For example, a LineString forming the letter 'S' is simple because it never comes in contact with itself.  But, a LineString that forms a Figure-Eight (8) is &lt;u&gt;not&lt;/u&gt; simple because it would have to cross over itself.  Likewise, two circles (MultiPolygon) stacked on top of each other to form a Figure-Eight would &lt;u&gt;not&lt;/u&gt; be simple because they touch each other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VALID:&lt;/strong&gt; A Geometry can cross over itself, but it cannot legally trace over itself.  That is, picture a LineString that backtracks over itself at some point, kind of like how I write my letter "P".  This is not considered to be Valid.&lt;/p&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="41" alt="Spatial_6_4" width="51" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A265/Spatial_6_4_3.png" /&gt; &lt;/p&gt;
&lt;p&gt;Tip: SQL Server will allow an invalid &lt;strong&gt;Geometry&lt;/strong&gt; to be instantiated, and Microsoft has provided an extension method called &lt;font face="monospace"&gt;MakeValid()&lt;/font&gt; that will convert the invalid instance into a valid instance.  In the letter "P" example, instead of the vertical line going down and then back up (as I draw it by hand), the valid form will eliminate the duplication of points simply by start at the bottom and going up (so that the LineString never traces over itself).  If it's not possible to simplify a shape in this way so that there is only one continuous path, then it will be broken up into multiple valid shapes (i.e., a MultiLineString, etc).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STX, STY, Z, M&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
Individual coordinates of a Point can be accessed via the OGC Standard properties STX and STY.  Three-dimensional Points also have a Z coordinate, which can be accessed via Microsoft's extended Z property.  Likewise, four-dimensional Points have a M (for Measure) coordinate, which can be accessed via Microsoft's extended M property.  If Z or M is not defined for a given point, then NULL will be returned.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g geometry = &lt;span class="str"&gt;'POINT(1 2)'&lt;/span&gt;
&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @h geometry = &lt;span class="str"&gt;'POINT(1 2 3 4)'&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STX, @g.STY, @g.Z, @g.M
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @h.STX, @h.STY, @h.Z, @h.M

Results:

1    2    &lt;span class="kwrd"&gt;NULL&lt;/span&gt;    &lt;span class="kwrd"&gt;NULL&lt;/span&gt;
1    2    3       4&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STPointOnSurface&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
When working with spatial data, especially without using a viewer, it can be kind of difficult to pick an arbitrary point that is inside of a Polygon (or on a LineString).  Thankfully, the OGC standard method &lt;font face="monospace"&gt;STPointOnSurface()&lt;/font&gt; does just that.  Given a &lt;strong&gt;Geometry&lt;/strong&gt; instance, it will return a somewhat random point that is guaranteed to be located within the interior of that instance.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g geometry = &lt;span class="str"&gt;'POLYGON((10 10, 14 15, 50 12, 45 30, &lt;br /&gt;                                10 30, 10 10))'&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STPointOnSurface().ToString()

Results:

POINT (23 25)&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="141" alt="Spatial_6_5" width="208" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A265/Spatial_6_5_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STSrid&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
All of my examples to this point have used the default Spatial Reference ID of 0 (for the &lt;strong&gt;Geometry&lt;/strong&gt; type) simply because I have not been specifying one.  The SRID is the mechanism that defines one geometry as being based on a different set of parameters than a geometry with a different SRID.  &lt;/p&gt;
&lt;p&gt;For example, you may have a set of shapes defined where each unit represents one meter, while another set of shapes is based on a reference system where each unit represents 1.5 inches.  It's totally legal to mix these shapes together the same column of a table in your database, provided that you assign a different SRID to each.  SQL Server does not need to know what units represent, because it will never permit the interaction of a shape from one SRID with a shape from another SRID.  &lt;/p&gt;
&lt;p&gt;The OGC standard property STSrid will get (or set) the SRID of the Geometry instance.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- @g will have the default SRID = 0&lt;br /&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g GEOMETRY = &lt;span class="str"&gt;'POLYGON((10 10, 10 40, 40 40, 10 10))'&lt;/span&gt;

&lt;span class="rem"&gt;-- @h is defined with SRID = 123&lt;br /&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @h GEOMETRY
    = GEOMETRY::STGeomFromText(&lt;span class="str"&gt;'POLYGON((10 10, 40 10, 
                                         40 40, 10 10))'&lt;/span&gt;, 
                               123)

&lt;span class="kwrd"&gt;select&lt;/span&gt; @g.STUnion(@h).ToString()

&lt;span class="rem"&gt;-- Returns NULL because of different SRIDs.  But, let's change&lt;br /&gt;&lt;br /&gt;-- @g to use SRID = 123&lt;/span&gt;

&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g.STSrid = 123

&lt;span class="kwrd"&gt;select&lt;/span&gt; @g.STUnion(@h).ToString()

&lt;span class="rem"&gt;-- Returns POLYGON ((10 10, 40 10, 40 40, 10 40, 10 10))&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Jason, What's Next?&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
Enough of this flat Earth stuff!  In the next part, I'll explore the Geography data type.  This is where things really start to get interesting.  Stay tuned!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;SQL Server 2008: Spatial Data, Part 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;SQL Server 2008: Spatial Data, Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx"&gt;SQL Server 2008: Spatial Data, Part 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx"&gt;SQL Server 2008: Spatial Data, Part 4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx"&gt;SQL Server 2008: Spatial Data, Part 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx"&gt;(next part) SQL Server 2008: Spatial Data, Part 7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx"&gt;SQL Server 2008: Spatial Data, Part 8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f04%2f11%2fsql-server-2008-spatial-data-part-6.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f04%2f11%2fsql-server-2008-spatial-data-part-6.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/39.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx</guid>
            <pubDate>Sat, 12 Apr 2008 00:44:19 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/39.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/39.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/39.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2008: Spatial Data, Part 5</title>
            <link>http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx</link>
            <description>&lt;p&gt;In &lt;a target="_blank" href="http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx"&gt;the previous part&lt;/a&gt; of this series, I demonstrated instance methods that transformed a single &lt;strong&gt;Geometry&lt;/strong&gt; type into another useful &lt;strong&gt;Geometry&lt;/strong&gt;.  In this post, we'll go a step further and show methods that allow two or more instances to interact with one another in order to produce a new &lt;strong&gt;Geometry&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For my baseline, I'll use two Polygons that overlap each other:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g geometry 
        = &lt;span class="str"&gt;'POLYGON((10 10, 40 10, 40 40, 10 40, 10 10))'&lt;/span&gt;
&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @h geometry 
        = &lt;span class="str"&gt;'POLYGON((30 30, 50 30, 50 50, 30 50, 30 30))'&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="63" alt="Spatial_5_1" width="68" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_1_3.png" /&gt; &lt;/p&gt;
&lt;h2&gt;STDifference&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
&lt;font face="monospace"&gt;STDifference()&lt;/font&gt; returns a new instance consisting of all points from the base instance that do not contain points from the parameter instance.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;span class="kwrd"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STDifference(@h).ToString();

&lt;span class="kwrd"&gt;&lt;font color="#000000"&gt;Result&lt;/font&gt;&lt;/span&gt;:

POLYGON ((10 10, 40 10, 40 30, 30 30, 30 40, 10 40, 10 10))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="63" alt="Spatial_5_2" width="68" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_2_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STIntersection&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
&lt;font face="monospace"&gt;STIntersection()&lt;/font&gt; returns a new instance containing only the points that are in common between the base instance and the parameter instance.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STIntersection(@h).ToString();

&lt;span class="kwrd"&gt;Result&lt;/span&gt;:

POLYGON ((30 30, 40 30, 40 40, 30 40, 30 30))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="63" alt="Spatial_5_3" width="68" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_3_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STSymDifference&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
&lt;font face="monospace"&gt;STSymDifference()&lt;/font&gt; returns a new instance containing only the points that are unique to both the base instance and the parameter instance (i.e., it excludes the points that &lt;font face="monospace"&gt;STIntersection()&lt;/font&gt; would return).&lt;/p&gt;
&lt;p&gt;In this case, the set of points is actually two different Polygons.  Because &lt;font face="monospace"&gt;STSymDifference()&lt;/font&gt; needs to return a single instance of &lt;em&gt;something&lt;/em&gt;, it will wrap those two Polygons into a collection (MultiPolygon).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STSymDifference(@h).ToString();

&lt;span class="kwrd"&gt;Result&lt;/span&gt;:

MULTIPOLYGON (((40 30, 50 30, 50 50, 30 50, 30 40, 40 40, 40 30)), 
              ((10 10, 40 10, 40 30, 30 30, 30 40, 10 40, 10 10)))&lt;/pre&gt;
&lt;p&gt; &lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="63" alt="Spatial_5_4" width="68" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_4_6.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STUnion&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
&lt;font face="monospace"&gt;STUnion()&lt;/font&gt; returns a new instance containing all of the points of the base instance and the parameter instance merged together.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STUnion(@h).ToString();

Results:

POLYGON ((10 10, 40 10, 40 30, 50 30, 50 50, 30 50, &lt;br /&gt;          30 40, 10 40, 10 10))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="63" alt="Spatial_5_5" width="68" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_5_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Blended Types&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
The instance methods described above do not work just for Polygons.  You can actually use them on different types, or even collections of different types.  &lt;/p&gt;
&lt;p&gt;For instance, if we look at the results of using a LineString as the base instance and a Polygon as the parameter instance, &lt;font face="monospace"&gt;STDifference()&lt;/font&gt; will return a MultiLineString constisting of the points from the original LineString that do not lie within the Polygon: &lt;br /&gt;
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g geometry = &lt;span class="str"&gt;'LINESTRING(9 9, 40 40)'&lt;/span&gt;
&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @h geometry = &lt;span class="str"&gt;'POLYGON((15 15, 15 30, 30 30, 30 15, 15 15))'&lt;/span&gt;
&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STDifference(@h).ToString();

Results:

MULTILINESTRING ((40 40, 30 30), (15 15, 9 9))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="51" alt="Spatial_5_6" width="60" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_6_6.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;font face="monospace"&gt;STIntersection()&lt;/font&gt; will return the points from the original LineString that do lie within the Polygon: &lt;br /&gt;
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STIntersection(@h).ToString();

Results:

LINESTRING (30 30, 15 15)&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="51" alt="Spatial_5_7" width="60" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_7_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;font face="monospace"&gt;STUnion()&lt;/font&gt; cannot determine a single common Geometry type, so it will return a mixed collection of types:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STUnion(@h).ToString();

Results:

GEOMETRYCOLLECTION 
(
     LINESTRING (40 40, 30 30), 
     POLYGON ((15 15, 30 15, 30 30, 15 30, 15 15)), 
     LINESTRING (15 15, 9 9)
)&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="51" alt="Spatial_5_8" width="60" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart5_A67F/Spatial_5_8_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;SQL Server 2008: Spatial Data, Part 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;SQL Server 2008: Spatial Data, Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx"&gt;SQL Server 2008: Spatial Data, Part 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx"&gt;SQL Server 2008: Spatial Data, Part 4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx"&gt;(next part) SQL Server 2008: Spatial Data, Part 6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx"&gt;SQL Server 2008: Spatial Data, Part 7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx"&gt;SQL Server 2008: Spatial Data, Part 8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f04%2f07%2fsql-server-2008-spatial-data-part-5.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f04%2f07%2fsql-server-2008-spatial-data-part-5.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/37.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx</guid>
            <pubDate>Mon, 07 Apr 2008 15:51:00 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/37.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/37.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/37.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2008: Spatial Data, Part 4</title>
            <link>http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx</link>
            <description>&lt;p&gt;In this, the 4th post in a series (&lt;a target="_blank" href="http://jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;Part 1&lt;/a&gt;, &lt;a target="_blank" href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;Part 2&lt;/a&gt;, &lt;a target="_blank" href="http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx"&gt;Part 3&lt;/a&gt;) on the new spatial data types in SQL Server 2008, I'll explain some of the methods that are used to transform a single &lt;strong&gt;Geometry&lt;/strong&gt; instance into another useful &lt;strong&gt;Geometry&lt;/strong&gt; instance.  Note that I'm using &lt;strong&gt;Geometry&lt;/strong&gt; for simplicity, &lt;strike&gt;but these techniques also work with &lt;strong&gt;Geography&lt;/strong&gt;&lt;/strike&gt;.  &lt;em&gt;&lt;strong&gt;Edit&lt;/strong&gt;: Ok, after starting to take a hard look at Geography, I realized that A LOT of the methods that Geometry offers are not implemented in Geography.  :-/  Sorry to mislead you.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;fieldset style="PADDING-RIGHT: 5px; PADDING-LEFT: 5px; PADDING-BOTTOM: 5px; PADDING-TOP: 5px"&gt;&lt;legend&gt;Useful Tip&lt;/legend&gt;To help me to visualize geometries as I explore the capabilities of the spatial data type, I've been using &lt;a target="_blank" href="http://www.codeplex.com/SpatialViewer"&gt;SpatialViewer&lt;/a&gt;, a tool written by fellow SQL Server MVP &lt;a target="_blank" href="http://sqlblogcasts.com/blogs/simons/"&gt;Simon Sabin&lt;/a&gt;. &lt;/fieldset&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;As a baseline, I'll be using my highest quality, hand-drawn letter "S".  This LineString is a simple geometry (it does not cross over itself), but is not closed (the starting and ending points are not the same).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g GEOMETRY
&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g = &lt;span class="str"&gt;'LINESTRING (  69 26, 69 23, 69 21, 67 20, 65 20, 
          63 18, 58 17, 52 17, 51 17, 49 17, 45 18, 44 20, 
          44 21, 42 26, 42 29, 42 32, 42 35, 43 35, 47 38, 
          50 41, 55 42, 58 42, 65 44, 66 44, 67 44, 68 45, 
          69 47, 70 48, 70 50, 71 51, 70 56, 68 60, 68 63, 
          66 65, 65 66, 63 68, 60 71, 59 71, 57 71, 55 71, 
          51 69, 45 65, 44 63, 42 62, 41 59, 41 57, 41 56, 
          41 54, 42 53 )'&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[






.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;style type="text/css"&gt;&lt;![CDATA[







.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="86" alt="Spatial_S_1" width="119" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_1_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STEnvelope&lt;/h2&gt;
&lt;p&gt;A bounding box is a rectangle that is defined by the combination of minimum and maximum X and Y values found in a given &lt;strong&gt;Geometry&lt;/strong&gt; instance.  The OGC standard method &lt;font face="monospace"&gt;STEnvelope()&lt;/font&gt; returns the bounding box (a Polygon) for the instance on which it is invoked.  All points of the original instance lie within the new Polygon.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: In the following T-SQL examples, I will trail the method calls with a ToString() so that we can examine the resulting WKT.  Normally, you would just work with the geometry (i.e., you wouldn't need call ToString())..&lt;/em&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STEnvelope().ToString()

Result:

POLYGON ((41 17, 71 17, 71 71, 41 71, 41 17))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="92" alt="Spatial_S_4" width="116" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_4_3.png" /&gt; &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: In these pictures, the original geometry is drawn in black, and the new geometry is superimposed in red.  If the new geometry has area, then that area will appear as light brown or tan.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STConvexHull&lt;/h2&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="95" alt="biten_apple_xl" width="110" align="right" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/biten_apple_xl_3.jpg" /&gt; If something is convex, then it is thought of as having a surface that is curved or rounded outward from the center.  For example, the side of an apple is convex.  If you happen to take a bite out of the apple, however, then that the portion that has been removed is considered to be concave.  To "correct" the concave portion of the half-eaten apple, we could fill in the hole with something like clay, but we would only need to restore enough material so that there was a straight line from the top of the hole to the bottom (and the same for side to side).&lt;/p&gt;
&lt;p&gt;The OGC standard method &lt;font face="monospace"&gt;STConvexHull()&lt;/font&gt; returns the minimal bounding convex Polygon for a geometry instance.  That is, any convex parts of the original instance will be preserved, and any concave parts will be "filled in", so to speak, by defining a straight line to bypass them.  Like &lt;font face="monospace"&gt;STEnvelope()&lt;/font&gt;, all points of the original instance lie within the new Polygon. &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STConvexHull().ToString()

Result:

POLYGON ((71 51, 70 56, 68 63, 66 65, 65 66, 63 68, 60 71, 
          59 71, 57 71, 55 71, 51 69, 45 65, 42 62, 41 59, 
          41 57, 41 56, 41 54, 42 26, 44 20, 45 18, 49 17, 
          51 17, 52 17, 58 17, 63 18, 67 20, 69 21, 71 51))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="93" alt="Spatial_S_2" width="125" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_2_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STBuffer&lt;/h2&gt;
&lt;p&gt;What if you have an existing shape, and you want to make it bigger, but preserve the general... uh, shape of it?  Then you would use the OGC standard method &lt;font face="monospace"&gt;STBuffer(distance)&lt;/font&gt;!  This method returns a Polygon that inflates the &lt;u&gt;area&lt;/u&gt; around the original geometry instance by a number of units that you provide.  Note that if the original instance is a Point, then the result will be a circle with a radius of the number of units that you provided.  It is also possible to deflate an existing Polygon by supplying a negative buffer value.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STBuffer(5).ToString()

Result:

POLYGON ((49 12, 51 12, 52 12, 58 12, 
          58.246719360351562 12.00609016418457, 
          58.492688179016113 12.024333953857422, 
          58.737458229064941 12.054683685302734, 
          58.98058032989502 12.097097396850586, 
          &lt;em&gt;(... snipped for clarity ...)
&lt;/em&gt;          48.693824768066406 12.009382247924805, 49 12))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="93" alt="Spatial_S_3" width="117" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_3_3.png" /&gt; &lt;/p&gt;
&lt;p&gt;What happens if the amount of buffering forces the inflated area to overlap with itself?  The resulting Polygon may develop holes (the area within a hole is still considered part of the exterior of the Polygon).  Here the buffer increases to 8, creating a hole:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STBuffer(8).ToString()

Result:

POLYGON (( exterior &lt;em&gt;ring points&lt;/em&gt; ), ( &lt;em&gt;interior ring points&lt;/em&gt; ))&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="93" alt="Spatial_S_5" width="125" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_5_3.png" /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;STExteriorRing, STInteriorRingN&lt;/h2&gt;
&lt;p&gt;The result of the very last example was a Polygon with one interior hole.  OGC standards provide a way to access the various components of a polygon (exterior ring and interior rings) individually.  &lt;br /&gt;
&lt;br /&gt;
&lt;font face="monospace"&gt;STExteriorRing()&lt;/font&gt; returns just the closed LineString of the Polygon itself.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STBuffer(8).STExteriorRing().ToString()

Result:

LINESTRING (&lt;strong&gt;49 9&lt;/strong&gt;, 51 9, 52 9, 58 9, 
            58.394750595092773 9.0097446441650391, 
            &lt;em&gt;(... snipped for clarity ...)
&lt;/em&gt;            48.022533416748047 9.0599403381347656, 
            48.5101203918457 9.0150127410888672, &lt;strong&gt;49 9&lt;/strong&gt;)&lt;/pre&gt;
&lt;p&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="93" alt="Spatial_S_6" width="124" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_6_3.png" /&gt; &lt;/p&gt;
&lt;p&gt;Similarly, &lt;font face="monospace"&gt;STInteriorRingN(n)&lt;/font&gt; is used to return the closed LineString of interior rings.  &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: This method is accessing a member of a GeomCollection by index, which I plan to cover in a later post.  What's important to know now is that indexing starts at 1, and you will get an error if you specify an index that does not actually exist in the collection.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;em&gt;&lt;/em&gt;&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.STBuffer(8).STInteriorRingN(1).ToString()

Result:

LINESTRING (48.893725268961383 48.937175344014442, 
            49.084709167480469 49.279642105102539, 
            &lt;em&gt;(... snipped for clarity ...)&lt;/em&gt;
            48.893725268961383 48.937175344014442)&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="89" alt="Spatial_S_7" width="123" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_7_3.png" /&gt; &lt;/pre&gt;
&lt;pre class="csharpcode"&gt; &lt;/pre&gt;
&lt;h2&gt;Extended Methods&lt;/h2&gt;
&lt;p&gt;Microsoft has implemented some additional methods on &lt;strong&gt;Geometry&lt;/strong&gt; instances to perform tasks that are beyond the scope of the OGC standards.&lt;/p&gt;
&lt;p&gt;&lt;font face="monospace"&gt;Reduce(tolerance)&lt;/font&gt; is a method that will simplify a given instance using the &lt;a target="_blank" href="http://everything2.com/index.pl?node_id=859282"&gt;Douglas-Peucker algorithm&lt;/a&gt;.  The result is a an approximation of the original instance containing a fewer number of points.  The accuracy of the new shape improves as the provided tolerance value approaches zero, but more points are necessary to provide that accuracy.  &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.Reduce(5).ToString()

Result:

LINESTRING (69 26, 49 17, 42 26, 42 35, 70 48, 
            60 71, 42 62, 42 53)
&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="90" alt="Spatial_S_8" width="124" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_8_3.png" /&gt; &lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;font face="monospace"&gt;BufferWithTolerance(distance, tolerance, relative)&lt;/font&gt; is very similar in function to &lt;font face="monospace"&gt;STBuffer()&lt;/font&gt;, only it gives you more control over the accuracy of the result.  The tolerance parameter, like in the Reduce() method, controls the amount of acceptable error a resulting line segment can be from what is ideal.  &lt;/p&gt;
&lt;p&gt;To understand how tolerance factors into the result, then picture a Point that is buffered into a circle.  To truly represent a circle, we would need a Polygon consisting of a infinite number of points.  This is not practical, but by allowing for error, we can generate a regular Polygon with any number of sides that behaves like a circle.  Smaller tolerances result in Polygons with a very large number of very small sides.  Likewise, larger tolerances result in Polygons with fewer sides, and your circle will start to resemble things like octagons, hexagons, and even squares.&lt;/p&gt;
&lt;p&gt;Compare the image below generated with a less accurate tolerance (left image), to the &lt;font face="monospace"&gt;STBuffer(8)&lt;/font&gt; example from above (right image).  The difference is subtle, primarily because the scale that we're working with is pretty small.  But, one difference to note is that the ends of the inflated "S" on the left are straight while the ones on the right are rounded.  Overall, the the image on the right has more points, and thus is a more accurate the original "S" shape than the image on the left.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @g.BufferWithTolerance(8, 10, 0).ToString()

Result:

POLYGON (( &lt;em&gt;ring points&lt;/em&gt; ), ( &lt;em&gt;hole points&lt;/em&gt; ))&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="97" alt="Spatial_S_9" width="131" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_9_3.png" /&gt; &lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="93" alt="Spatial_S_5" width="125" border="0" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/SQLServer2008SpatialDataPart4_B98F/Spatial_S_5_6.png" /&gt; &lt;/pre&gt;
&lt;p&gt;&lt;a href="http://www.jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;SQL Server 2008: Spatial Data, Part 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;SQL Server 2008: Spatial Data, Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx"&gt;SQL Server 2008: Spatial Data, Part 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx"&gt;(next part) SQL Server 2008: Spatial Data, Part 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx"&gt;SQL Server 2008: Spatial Data, Part 6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx"&gt;SQL Server 2008: Spatial Data, Part 7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx"&gt;SQL Server 2008: Spatial Data, Part 8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f04%2f03%2fsql-server-2008-spatial-data-part-4.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjasonfollas.com%2fblog%2farchive%2f2008%2f04%2f03%2fsql-server-2008-spatial-data-part-4.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/36.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx</guid>
            <pubDate>Fri, 04 Apr 2008 00:31:31 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/36.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/36.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/36.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2008: Spatial Data, Part 3</title>
            <link>http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx</link>
            <description>&lt;p&gt;In the previous parts of this series (&lt;a title="SQL Server 2008: Spatial Data, Part 1" target="_blank" href="http://jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;Part 1&lt;/a&gt;, &lt;a title="SQL Server 2008: Spatial Data, Part 2" target="_blank" href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;Part 2&lt;/a&gt;), I introduced the &lt;strong&gt;Geometry&lt;/strong&gt; and &lt;strong&gt;Geography&lt;/strong&gt; data types, the various subclasses (Point, LineString, Polygon, etc), and demonstrated a little bit of the Well-Known Text (WKT) syntax.  These two posts were primarily informational in nature, and didn't touch SQL Server at all.  Let's change that!&lt;/p&gt;
&lt;h2&gt;Instantiating the UDT&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;Geometry&lt;/strong&gt; and &lt;strong&gt;Geography&lt;/strong&gt; data types are implemented as User Defined Types (UDT) written in .NET.  They are automatically installed with the server, and are available for use by any SQL Server 2008 database.  For this post, I will use the &lt;strong&gt;Geometry&lt;/strong&gt; type to demonstrate capability, &lt;strike&gt;but the &lt;strong&gt;Geography&lt;/strong&gt; type has the very same capabilities&lt;/strike&gt; (the primary difference between the two types is how distance and area is calculated). &lt;em&gt; &lt;strong&gt;Edit&lt;/strong&gt;: After taking a hard look at Geography, I realized that a lot of methods that Geometry offers are not implemented.  So, I was incorrect in my assertion that everything available in Geometry is also available in Geography.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Any variable, parameter, or table column can be declared as type &lt;strong&gt;Geometry&lt;/strong&gt;.  Notice that the type name is not case sensitive.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&lt;/span&gt; &lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g Geometry&lt;/pre&gt;
&lt;pre class="csharpcode"&gt; &lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;As mentioned before, &lt;strong&gt;Geometry&lt;/strong&gt; by itself is abstract.  In order to do something interesting, you need to instantiate the type as one of the concrete subclasses of the &lt;strong&gt;Geometry&lt;/strong&gt; type.  Adhering to the OGC standards, you can use the &lt;font face="monospace"&gt;STGeomFromText()&lt;/font&gt; static method to parse data provided in valid WKT syntax, and then your variable will take on the characteristics of the defined subclass (i.e., it will be instantiated as one of the concrete types).  Note that in SQL syntax, CLR method names &lt;strong&gt;&lt;u&gt;are&lt;/u&gt;&lt;/strong&gt; case sensitive, so &lt;font face="monospace"&gt;stgeomfromtext()&lt;/font&gt; will not work.&lt;/p&gt;
&lt;p&gt;Now, in C# and VB.NET, it is common to invoke static methods of a type using a dot notation, as in &lt;font face="monospace"&gt;geometry.STGeomFromText()&lt;/font&gt;.  However, this is not the case in T-SQL, because that particular syntax implies that you're calling a User Defined Function belonging to the "geometry" schema.  Instead, when calling a static method belonging to a type, you separate the type name and the method name using two colons (::).&lt;/p&gt;
&lt;p&gt;For example, to use &lt;font face="monospace"&gt;STGeomFromText()&lt;/font&gt; to create a LineString, you would do the following:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g Geometry
&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g = Geometry::STGeomFromText(&lt;span class="str"&gt;'LINESTRING(0 0, 10 10, 21 2)'&lt;/span&gt;,&lt;br /&gt;                                  0)&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;You might be wondering, "What's that weird zero at the end all about?"  In &lt;a title="SQL Server 2008: Spatial Data, Part 1" target="_blank" href="http://jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;Part 1&lt;/a&gt;, I touched on the concept of a Spatial Reference System that defines things such as the unit of measure and the dimensions of the world being represented, etc.  The zero in this method call is the Spatial Reference ID (SRID) parameter, and it is required that the SRID being used is declared alongside any piece of spatial information.  SQL Server 2008 will not perform calculations on pieces of spatial information that belong to separate Spatial Reference Systems (because one system may use centimeters, and another may use miles, and SQL Server simply does not have the means to automatically convert units).  For the &lt;strong&gt;Geometry&lt;/strong&gt; type, it is common to just use zero for the SRID when all of your data is from the same Spatial Reference System (&lt;strong&gt;Geography&lt;/strong&gt; uses 4326 as the default, to be explained later).&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;Note: A linebreak was inserted between the parameters in order to make it obvious to the eye.  There is no requirement in T-SQL that requires the linebreak.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since we were declaring a LineString specifically, we could have also used a static method that only accepts valid LineStrings as input:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g Geometry
&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g = Geometry::STLineFromText(&lt;span class="str"&gt;'LINESTRING(0 0, 10 10, 21 2)'&lt;/span&gt;,&lt;br /&gt;                                  0)&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;If we tried to supply something that was not valid WKT for a LineString, like &lt;font face="monospace"&gt;POINT(0 0)&lt;/font&gt;,then a .NET FormatException would have been thrown:&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New" color="#ff0000" size="1"&gt;Msg 6522, Level 16, State 1, Line 2 &lt;br /&gt;
A .NET Framework error occurred during execution of user-defined routine or aggregate "geometry": &lt;br /&gt;
System.FormatException: 24142: Expected LINESTRING at position 0. The input has POINT(0 0). &lt;br /&gt;
System.FormatException: &lt;br /&gt;
   at Microsoft.SqlServer.Types.OpenGisWktReader.RecognizeToken(String token) &lt;br /&gt;
   at Microsoft.SqlServer.Types.OpenGisWktReader.ParseLineStringTaggedText() &lt;br /&gt;
   at Microsoft.SqlServer.Types.OpenGisWktReader.ReadLineString() &lt;br /&gt;
   at Microsoft.SqlServer.Types.SqlGeometry.STLineFromText(SqlChars lineStringTaggedText, Int32 srid)&lt;/font&gt; &lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;The entire list of OGC standard static methods on the Geometry type include: STGeomFromText, STPointFromText, STLineFromText, STPolyFromText, STMPointFromText, STMLineFromText, STMPolyFromText, STGeomCollFromText, STGeomFromWKB, STPointFromWKB, STLineFromWKB, STPolyFromWKB, STMPointFromWKB, STMLineFromWKB, STMPolyFromWKB, and STGeomCollFromWKB.  &lt;em&gt;Note: The "FromWKB" methods are the "Well-Known Binary" equivalents to the "FromText" methods, and accept a specially crafted array of bytes as the input.  Using binary representations for initialization improves performance, but is much harder for humans to work with and comprehend.&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;There is one other trick to be aware of when initializing a spatial data type.  By contract, a UDT in SQLCLR must support serialization to and from a string.  That is, a UDT must implement a &lt;font face="monospace"&gt;ToString()&lt;/font&gt; method and a &lt;font face="monospace"&gt;Parse(string)&lt;/font&gt; method that are called implicitly when a conversion is required, but these two methods can also be explicitly invoked.  It just so happens that the string format used by the &lt;strong&gt;Geometry&lt;/strong&gt; type is WKT (actually, the &lt;font face="monospace"&gt;Parse()&lt;/font&gt; method is identical to STGeomFromText() with an implicit SRID of zero). &lt;/p&gt;
&lt;p&gt;All of the following are functionally equivalent:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g Geometry

&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g = Geometry::STGeomFromText(&lt;span class="str"&gt;'LINESTRING(0 0, 10 10, 21 2)'&lt;/span&gt;,&lt;br /&gt;                                  0)
&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g = Geometry::Parse(&lt;span class="str"&gt;'LINESTRING(0 0, 10 10, 21 2)'&lt;/span&gt;)
&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g = &lt;span class="str"&gt;'LINESTRING(0 0, 10 10, 21 2)'&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;&lt;em&gt;Note: The third example implicitly invokes the Parse(string) method.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;  &lt;/p&gt;
&lt;h2&gt;Working with a UDT Instance&lt;/h2&gt;
&lt;p&gt;Once you have created an instance, then you can use a dot notation to access instance properties and methods:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @g Geometry
&lt;span class="kwrd"&gt;SET&lt;/span&gt; @g = Geometry::STLineFromText(&lt;span class="str"&gt;'LINESTRING(0 0, 10 10, 21 2)'&lt;/span&gt;,&lt;br /&gt;                                  0)

&lt;span class="kwrd"&gt;PRINT&lt;/span&gt; @g.STLength() &lt;font color="#008000"&gt;-- Result: 27.7436&lt;/font&gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Up to this point, my example code has been declaring and instantiating spatial data as variables within a batch.  But, columns in a table can also be declared as spatial, and queries can access instance properties and methods:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; #demo
(
    ID    &lt;span class="kwrd"&gt;INT&lt;/span&gt; &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    G     GEOMETRY
)

INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; #demo (G)
&lt;span class="kwrd"&gt;VALUES&lt;/span&gt;    (&lt;span class="str"&gt;'LINESTRING(0 0, 10 10, 21 2)'&lt;/span&gt;),
          (&lt;span class="str"&gt;'LINESTRING(1 1, 11 11, 22 3)'&lt;/span&gt;),
          (&lt;span class="str"&gt;'POINT(5 5)'&lt;/span&gt;)

&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; ID, G.ToString() &lt;span class="kwrd"&gt;AS&lt;/span&gt; WKT, G.STLength() &lt;span class="kwrd"&gt;AS&lt;/span&gt; LENGTH
&lt;span class="kwrd"&gt;FROM&lt;/span&gt; #demo

&lt;span class="kwrd"&gt;DROP&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; #demo&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;Results:&lt;/p&gt;
&lt;table cellspacing="0" cellpadding="2" width="400" border="1"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;strong&gt;ID&lt;/strong&gt;&lt;/td&gt;
            &lt;td valign="top"&gt;&lt;strong&gt;WKT&lt;/strong&gt;&lt;/td&gt;
            &lt;td valign="top"&gt;&lt;strong&gt;LENGTH&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top"&gt;1&lt;/td&gt;
            &lt;td valign="top"&gt;LINESTRING (0 0, 10 10, 21 2)&lt;/td&gt;
            &lt;td valign="top"&gt;27.7436061324664&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top"&gt;2&lt;/td&gt;
            &lt;td valign="top"&gt;LINESTRING (1 1, 11 11, 22 3) &lt;/td&gt;
            &lt;td valign="top"&gt;27.7436061324664&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top"&gt;3&lt;/td&gt;
            &lt;td valign="top"&gt;POINT (5 5)&lt;/td&gt;
            &lt;td valign="top"&gt;0&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Instance methods are the exciting part of using the spatial data types in SQL Server 2008.  In the next part of this series, I will cover individual methods in detail.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx"&gt;SQL Server 2008: Spatial Data, Part 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/03/27/sql-server-2008-spatial-data-part-2.aspx"&gt;SQL Server 2008: Spatial Data, Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/03/sql-server-2008-spatial-data-part-4.aspx"&gt;(next part) SQL Server 2008: Spatial Data, Part 4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/07/sql-server-2008-spatial-data-part-5.aspx"&gt;SQL Server 2008: Spatial Data, Part 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/04/11/sql-server-2008-spatial-data-part-6.aspx"&gt;SQL Server 2008: Spatial Data, Part 6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/05/16/sql-server-2008-spatial-data-part-7.aspx"&gt;SQL Server 2008: Spatial Data, Part 7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx"&gt;SQL Server 2008: Spatial Data, Part 8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.jasonfollas.com%2fblog%2farchive%2f2008%2f03%2f28%2fsql-server-2008-spatial-data-part-3.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.jasonfollas.com%2fblog%2farchive%2f2008%2f03%2f28%2fsql-server-2008-spatial-data-part-3.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/34.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx</guid>
            <pubDate>Fri, 28 Mar 2008 20:06:01 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/34.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2008/03/28/sql-server-2008-spatial-data-part-3.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/34.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/34.aspx</trackback:ping>
        </item>
    </channel>
</rss>