ptg 1604 CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008 Now, if you run another update but only specify a value for Weight in the XML string, the Color column is set to NULL: Update Product_sparse set ProductInfo = ‘<Weight>.10</Weight>’ where productID = 5 SELECT productID, productName, Color, Weight, SEllEndDate FROM Product_sparse where productID = 5 go productID productName Color Weight SEllEndDate 5 ValveStem NULL 0.10 NULL However, if you reference the sparse columns explicitly in an UPDATE statement, the other values remain unchanged: Update Product_sparse set Color = ‘silver’ where ProductID = 5 SELECT productID, productName, Color, Weight, SEllEndDate FROM Product_sparse where productID = 5 go productID productName Color Weight SEllEndDate 5 ValveStem silver 0.10 NULL Column sets are most useful when you have many sparse columns in a table (for example, hundreds) and operating on them individually is cumbersome. Your client applications may more easily and efficiently generate the appropriate XML string to populate the column set rather than your having to build an UPDATE statement dynamically to deter- mine which of the sparse columns need to be included in the SET clause. Applications might actually see some performance improvement when they select, insert, or update data by using column sets on tables that have lots of columns. Sparse Columns: Good or Bad? There is some disagreement in the SQL Server community whether or not sparse columns are appropriate. A number of professionals are of the opinion that any table design that requires sparse columns is a bad design that does not follow good relational design guide- lines. Sparse columns, by their nature, are heavily denormalized. On the other hand, many times you have to live in the real world and make the best of a bad database design ptg 1605 Spatial Data Types 42 that you’ve inherited. Sparse columns can help solve performance and storage issues in databases that may have been poorly designed. Although sparse columns can solve certain kinds of problems with database design, you should never use them as an alternative to proper database and table design. As cool as sparse columns are, they aren’t appropriate for every scenario, particularly when you’re tempted to violate normalization rules to be able to cram more fields into a table. Spatial Data Types SQL Server’s support of SQLCLR allows for very rich user-defined types to be utilized. For example, a developer could create a single object that contains multiple properties and can also perform calculations internally (methods), yet still store it in a single column in a single row in a database table. This allows multiple complex types of data to be stored and queried in the database, instead of just strings and numbers. SQL Server 2008 makes use of SQLCLR to support two new .NET CLR data types for storing spatial data: GEOMETRY and GEOGRAPHY. These types support methods and properties that allow for the creation, comparison, analysis, and retrieval of spatial data. Spatial data types provide a comprehensive, high-performance, and extensible data storage solution for spatial data, enabling organizations of any scale to integrate geospatial features into their applications and services. The GEOMETRY data type is a .NET CLR data type that supports the planar model/data, which assumes a flat projection and is therefore sometimes called flat earth. Geometry data represents information in a uniform two-dimensional plane as points, lines, and polygons on a flat surface, such as maps and interior floor plans where the curvature of the earth does not need to be taken into account. For example, perhaps your user-defined coordinate space is being used to represent a warehouse facility. Within that coordinate space, you can use the GEOMETRY data type to define areas that represent storage bays within the warehouse. You can then store data in your database that tracks which inven- tory is located in which area. You could then query the data to determine which forklift driver is closest to a certain type of item, for example. The GEOGRAPHY data type provides a storage structure for geodetic data, sometimes referred to as round-earth data because it assumes a roughly spherical model of the world. It provides a storage structure for spatial data that is defined by latitude and longitude coor- dinates using an industry standard ellipsoid such as WGS84, the projection method used by Global Positioning System (GPS) applications. The SQL Server GEOGRAPHY data type uses latitude and longitude angles to identify points on the earth. Latitude measures how far north (or south) of the equator a point is, while longitude measures how far east (or west) of a prime meridian a point is. Note that this coordinate system can be used to identify points on any spherical object, be it a baseball, the earth, or even the moon. The GEOMETRY and GEOGRAPHY data types support seven instance types that you can create and work with in a database: . POINT—A POINT is an exact location and is defined in terms of an X and Y pair of coordinates, as well as optionally by Z (elevation) and M (measure) coordinates. It ptg 1606 CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008 does not have a length or any area associated with it. These instance types are used as the fundamental building blocks of more complex spatial types. . MULTIPOINT—A MULTIPOINT is a collection of zero or more points. . LINESTRING—A LINESTRING is the path between a sequence of points (that is, a series of connected line segments). It is considered simple if it does not cross over itself and is considered a ring if the starting point is the same as the ending point. A LINESTRING is always considered to be a one-dimensional object; it has length but does not have area (even if it is a ring). . MULTILINESTRING—A MULTILINESTRING is a collection of zero or more GEOMETRY or GEOGRAPHY LINESTRING instances. . POLYGON—A POLYGON is a closed two-dimensional shape defined by a ring. It has both length and area and has at least three distinct points. A POLYGON may also have holes in its interior (a hole is defined by another POLYGON). Area within a hole is consid- ered to be exterior to the POLYGON itself. . MULTIPOLYGON—A MULTIPOLYGON instance is a collection of zero or more POLYGON instances. . GEOMETRYCOLLECTION—A GEOMETRYCOLLECTION is a collection of zero or more GEOMETRY or GEOGRAPHY instances. A GEOMETRYCOLLECTION can be empty. This is simi- lar to a list or an array in most programming languages. The most generic type of collection is the GEOMCOLLECTION, whose members can be of any type. Representing Spatial Data The Open Geospatial Consortium, Inc. (OGC) is a nonprofit, international, voluntary consensus standards organization that is leading the development of standards for geospatial and location-based services. The OGC defines different ways to represent geospatial information as bytes of data that can then be interpreted by the GEOMETRY or GEOGRAPHY types as being POINTS, LINESTRINGS, and so on. SQL Server 2008 supports three such formats: . Well-Known Text (WKT) . Well-Known Binary (WKB) . Geography Markup Language (GML) For the purposes of this chapter, we stick to WKT examples because they are both concise and somewhat readable. The syntax of WKT is not too difficult to understand, so let’s look at some examples: . POINT(10 100)—Here, 10 and 100 represent X and Y values of the point. . POINT(10 100 10 1)—This example shows Z and M values in addition to X and Y. . LINESTRING(0 0, 10 100)—The first two values represent the starting point, and the last two values represent the end point of the line. ptg 1607 Spatial Data Types 42 . POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))—Each pair of numbers represents a point on the edge of the polygon. Note that the end point is the same as the starting point. Working with Geometry Data As mentioned previously, the geometry data type is implemented as a common language runtime (CLR) data type in SQL Server and is used to represent data in a Euclidean (flat) coordinate system. The GEOMETRY type is predefined and available in each database. Any variable, parameter, or table column can be declared with the GEOMETRY data type, and you can operate on geometry data in the same manner as you would use other CLR types using the built-in methods to create, validate, and query geometry data. NOTE SQL Server provides a number of methods for the GEOMETRY and GEOGRAPHY data types. Covering all the available methods is beyond the scope of this chapter. The examples provided here touch on some of the more common methods. For more information on other GEOMETRY and GEOGRAPHY methods, refer to SQL Server 2008 Books Online. To assign a value to a column or variable of type GEOMETRY, you must use one of the static methods to parse the representation of the data into the spatial data type. For example, to parse geometry data provided in a valid WKT syntax, you can use the STGeomFromText method: Declare @geom GEOMETRY Declare @geom2 GEOMETRY SET @geom = geometry::STGeomFromText(‘LINESTRING (100 100, 20 180, 180 180)’, 0) SET @geom2 = geometry::STGeomFromText (‘POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0))’, 0) NOTE The last parameter passed to the method is the spatial reference ID (SRID) parameter. The SRID is required. SQL Server 2008 does not perform calculations on pieces of spatial information that belong to separate spatial reference systems (for example, if one system uses centimeters and another uses miles, SQL Server simply does not have the means to automatically convert units). For the GEOMETRY type, the default SRID value is 0. The default SRID for GEOGRAPHY is 4326, which maps to the WGS 84 spatial reference system. If you are declaring a LINESTRING specifically, you can use the STLineFromText static method that accepts only valid LINESTRINGs as input: ptg 1608 CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008 Declare @geom GEOMETRY SET @geom = geometry::STLineFromText(‘LINESTRING (100 100, 20 180, 180 180)’, 0) The GEOMETRY type, like other SQLCLR UDTs, supports implicit conversion to and from a string. The string format supported by the GEOMETRY type for implicit conversion is WKT. Due to this feature, all the following SET statements are functionally equivalent (the last two SET statements use an implicit SRID of 0): DECLARE @geom GEOMETRY SET @geom = geometry::STLineFromText(‘LINESTRING (100 100, 20 180, 180 180)’, 0) set @geom = Geometry::Parse(‘LINESTRING (100 100, 20 180, 180 180)’) set @geom = ‘LINESTRING (100 100, 20 180, 180 180)’ After defining a GEOMETRY instance, you can use the CLR UDT dot notation to access other properties and methods of the GEOGRAPHY instance. For example, the following code uses the STLength() method to return the length of the LINESTRING: DECLARE @geom GEOMETRY SET @geom = geometry::STLineFromText(‘LINESTRING (100 100, 20 180, 180 180)’, 0) select @geom.STLength() as “Length” go Length 273.137084989848 The following example uses the STIntersection() method to return the points where two GEOMETRY instances intersect: DECLARE @geom1 GEOMETRY; DECLARE @geom2 GEOMETRY; DECLARE @result GEOMETRY; SET @geom1 = geometry::STGeomFromText(‘LINESTRING (100 100, 20 180, 180 180)’, 0) SET @geom2 = geometry::STGeomFromText(‘POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0))’, 0) SELECT @result = @geom1.STIntersection(@geom2); SELECT @result.STAsText(); go LINESTRING (50 150, 100 100) All the preceding examples use local variables in a batch. You also can declare columns in a table with the GEOMETRY type, and you can use the instance properties and methods against the columns as well: ptg 1609 Spatial Data Types 42 CREATE TABLE #geom_demo ( GeomID INT IDENTITY NOT NULL, GeomCol GEOMETRY ) INSERT INTO #geom_demo (GeomCol) VALUES (‘LINESTRING (100 100, 20 180, 180 180)’), (‘POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0))’), (‘POINT(10 10)’) SELECT GeomID, GeomCol.ToString() AS WKT, GeomCol.STLength() AS LENGTH, GeomCol.STArea() as Area FROM #geom_demo drop table #geom_demo go GeomID WKT LENGTH Area 1 LINESTRING (100 100, 20 180, 180 180) 273.137084989848 0 2 POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0)) 600 22500 3 POINT (10 10) 0 0 Working with Geography Data The GEOGRAPHY data type is also implemented as a .NET common language runtime data type in SQL Server. Unlike the GEOMETRY data type in which locations are defined in terms of X and Y coordinates that can conceivably extend to infinity, the GEOGRAPHY type repre- sents data in a round-earth coordinate system. Whereas flat models do not “wrap around,” the round-earth coordinate system does wrap around such that if you start at a point on the globe and continue in one direction, you eventually return to the starting point. Because defining points on a ball using X and Y is not very practical, the GEOGRAPHY data type instead defines points using angles. The SQL Server GEOGRAPHY data type stores ellip- soidal (round-earth) data as GPS latitude and longitude coordinates. Longitude represents the horizontal angle and ranges from -180 degrees to 180 degrees, and latitude represents the vertical angle and ranges from -90 degrees to 90 degrees. The GEOGRAPHY data type provides similar built-in methods as the GEOMETRY data type that you can use to create, validate, and query geography instances. ptg 1610 CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008 To assign a value to a geography column or variable, you can use the STGeogFromText methods to parse the parse geometry data provided in a valid WKT syntax into a valid geography value: Declare @geog GEOGRAPHY Declare @geog2 GEOGRAPHY SET @geog = geography::STGeomFromText(‘LINESTRING(-122.360 47.656, -122.343 47.656)’, 4326) SET @geog2 = geography::STGeomFromText(‘POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))’, 4326) As with the GEOMETRY data type, you can also use the STLineFromText static method that accepts only valid LINESTRINGS as input, or you can take advantage of the support for implicit conversion of WKT strings: DECLARE @geog GEOGRAPHY SET @geog = Geography::STLineFromText(‘LINESTRING (-122.360 47.656, -122.343 47.656)’, 4326) set @geog = Geography::Parse(‘LINESTRING (-122.360 47.656, -122.343 47.656)’) set @geog = ‘LINESTRING (-122.360 47.656, -122.343 47.656)’ The following code uses the STLength() and STArea() methods to return the length of the LINESTRING: DECLARE @geom GEOMETRY SET @geom = geometry::STLineFromText(‘LINESTRING (100 100, 20 180, 180 180)’, 0) select @geom.STLength() as “Length” go Length 273.137084989848 The preceding examples use local variables in a batch. You also can declare columns in a table using the geography data type, and you can use the instance properties and methods against the columns as well: CREATE TABLE #geog ( id int IDENTITY (1,1), ptg 1611 Spatial Data Types 42 GeogCol1 GEOGRAPHY, GeogCol2 AS GeogCol1.STAsText() ); GO INSERT INTO #geog (GeogCol1) VALUES (geography::STGeomFromText (‘LINESTRING(-122.360 47.656, -122.343 47.656)’, 4326)); INSERT INTO #geog (GeogCol1) VALUES (geography::STGeomFromText (‘POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))’, 4326)); GO DECLARE @geog1 GEOGRAPHY; DECLARE @geog2 GEOGRAPHY; DECLARE @result GEOGRAPHY; SELECT @geog1 = GeogCol1 FROM #geog WHERE id = 1; SELECT @geog2 = GeogCol1 FROM #geog WHERE id = 2; SELECT @result = @geog1.STIntersection(@geog2); SELECT Intersection = @result.STAsText(); go Intersection LINESTRING (-122.3479999999668 47.656000260658459 , -122.35799999998773 47.656000130309728) Spatial Data Support in SSMS When querying spatial data in SSMS, you’ll find that SSMS has a built-in capability to plot and display some basic maps of your spatial data. To demonstrate this, you can run the following query in the AdventureWorks2008R2 or AdventureWorks2008 database in SSMS: select SpatialLocation from person.Address a inner join person.StateProvince sp on a.StateProvinceID = sp.StateProvinceID and sp.CountryRegionCode = ‘US’ ptg 1612 CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008 After the query runs, you should see a Spatial Results tab next to the Results tab (see Figure 42.3). Click on this tab, and the location points are plotted on a map. Select the Bonne Projection. If you look closely, you can see that the geographical points plotted roughly provide an outline of the United States. If you mouse over one of the points, SSMS displays the associated address information displayed in the Person.Address table. In addition to displaying maps of geography data values, SSMS can also display geometry data, showing lines, points, and polygons in an X-Y grid. For example, if you run the following query and click on the Spatial Results tab, it should display a box like the one shown in Figure 42.4: declare @smallBox GEOMETRY = ‘polygon((0 0, 0 2, 2 2, 2 0, 0 0))’; select @smallbox If you want to display multiple polygons, points, or lines together at the same time, they have to be returned as multiple rows in a single table. If you return them as multiple columns, SSMS displays only one column at a time in the Spatial Results tab. For example, if you run the following query, SSMS displays two boxes, the polygon defined by the inter- section of the two boxes, as well as the overlapping line defined by the LineString, as shown in Figure 42.5: FIGURE 42.3 Displaying a map of Person.Address records in SSMS. ptg 1613 Spatial Data Types 42 FIGURE 42.4 Displaying a polygon in SSMS. FIGURE 42.5 Displaying intersecting polygons and an overlapping Line in SSMS. . New for Transact -SQL in SQL Server 2008 Declare @geom GEOMETRY SET @geom = geometry::STLineFromText(‘LINESTRING (100 100, 20 180, 180 180)’, 0) The GEOMETRY type, like other SQLCLR UDTs, supports. data to be stored and queried in the database, instead of just strings and numbers. SQL Server 2008 makes use of SQLCLR to support two new .NET CLR data types for storing spatial data: GEOMETRY. (elevation) and M (measure) coordinates. It ptg 1606 CHAPTER 42 What’s New for Transact -SQL in SQL Server 2008 does not have a length or any area associated with it. These instance types are used as