If you have been using SQL Server for some time, you’ve probably heard of the spatial data support. This might be particularly interesting for anyone who is using any desktop GIS for data management and analysis. If you are an ArcGIS user and have enterprise geodatabases stored within SQL Server databases, you might have wondered whether it is possible to interact with the spatial data. This is useful when you don’t have a chance to use ArcMap to access the database due to some restrictions (permissions, network connections or software compatibility).
Well, you actually can do a whole lot with your geographic data just with SQL. It is important that you define the Shape field as of the Geometry/Geography data type. For most of the GIS work, you’d probably choose Geometry type which represents data in a Euclidean (flat) coordinate system. As soon as you have a geodatabase feature class which has the Shape field defined as of Geometry type, you can use native SQL Server tools to interact both with the feature class attributes and geometry.
Beginning with ArcGIS 10.1, feature classes created in geodatabases in SQL Server use the Microsoft Geometry type by default. To move your existing feature classes to the Geometry storage type, use the Migrate Storage geoprocessing tool or a Python script.
Alright, so after you have copied your file geodatabase feature class into a SQL Server geodatabase, you are ready to use native SQL to interact with the spatial data.
Let’s select all the features from the Parcels feature class.
SELECT * FROM dbo.PARCELS
Because we have a SHAPE column that of Geometry type, we get another tab in the results grid – Spatial results. There you can see your geometries visualized.
Let’s see what coordinate system our feature class was defined in.
DECLARE @srid INT = (SELECT TOP 1 shape.STSrid FROM dbo.PARCELS) SELECT @srid AS SRID, srtext AS Name FROM sde.SDE_spatial_references WHERE auth_srid = @srid
Here we use <GeometryColumnName>.STSrid to get the spatial reference id (SRID) of the coordinate system of the first feature. Because our geographic data is stored in a projected coordinate system (and Geometry type), we cannot get its name by using core SQL Server spatial references table, sys.spatial_reference_systems.
Here is why:
The coordinate systems in this table are for the geography type only as it contains information about the ellipsoid that is required to perform calculations. No such information is required to perform calculations for projected coordinate systems on the plane used by the geometry type, so you are free to use any reference system you like. For the calculations done by the geometry type, it is the same no matter what you use.
Let us explore next what kind of geometry is stored within a table. It is possible to store different types of geometry (such as polygon and polyline) within one table in SQL Server.
Let us see if it is true:
SELECT Id,GeomData AS Geometry,GeomData.STAsText() AS GeometryData FROM [testgdb].[dbo].[GeneralizedData]
Yes indeed we store in one table features of different geometry and SQL Server has no problems with that. To be able to visualize this table in ArcMap though, you would need to use a query layer which is basically stand-alone table that is defined by a SQL query. ArcGIS can only handle having one type of geometry stored within each feature class which is why you will get a choice to pick what type of geometry do you want to look at.
After adding this layer into ArcMap, you will be able to see the polygons (provided you’ve chosen the polygons). The query layer is in read-only, so you cannot edit features in ArcMap. If you have a SQL Server table (non-registered with geodatabase) with multiple types of geometries stored, you will be able to switch easily between by adding multiple query layers into ArcMap defining what kind of geometry you want to work with.
Let us keep working with a geodatabase feature class which has only polygons. Let’s check if it’s true:
SELECT Shape.STGeometryType() AS GeometryType FROM dbo.PARCELS
Alright, so we know already what kind of coordinate system the data is stored in and we know that there are polygons. Let us get the perimeter (length) and the area of those polygons.
SELECT PARCEL_ID, SHAPE.STArea() AS Area, SHAPE.STLength() AS Perimeter FROM dbo.PARCELS
We can also get the coordinates of each polygon within our feature class. Note that that the start point and the end point are identical – that is because each polygon is considered to be closed:
SELECT Shape.STAsText() AS GeometryType FROM dbo.PARCELS
This is what we will get:
POLYGON ((507348.9687482774 687848.062502546, 507445.156252367 687886.06251058145, 507444.18750036607 687888.56250258372, 507348.9687482774 687848.062502546))
There are similar functions such as .STAsBinary() which returns the Open Geospatial Consortium (OGC) Well-Known Binary (WKB) representation of a geometry instance and .AsGml() which returns the Geography Markup Language (GML) representation of a geometry instance.
We can also check the number of vertices per polygon:
SELECT PARCEL_id, Shape.STAsText() AS GeometryDesc, Shape.STNumPoints() AS NumVertices FROM dbo.PARCELS ORDER BY NumVertices DESC
Alright, that was probably enough querying data. Let us check what kind of GIS analysis is available to us with native SQL. The easiest way to get started is probably to process the features of a feature class and then write the resultant geometries into a new table.
DROP TABLE [ParcelEnvelope] CREATE TABLE [dbo].[ParcelEnvelope]([Id] [int] NOT NULL, [PolyArea] int,[GeomData] [geometry] NOT NULL) ON [PRIMARY] INSERT INTO ParcelEnvelope (Id,GeomData,PolyArea) SELECT PARCEL_ID AS Id, SHAPE.STEnvelope() AS GeomData, SHAPE.STArea() AS PolyArea FROM dbo.PARCELS ORDER BY OBJECTID
This will create a new table where the envelopes of each parcel polygon will be written to.
Let us do some buffers on road centerlines geodatabase feature class:
DROP TABLE [RoadBuffer] CREATE TABLE [dbo].[RoadBuffer]([Id] [int] NOT NULL, [GeomData] [geometry] NOT NULL) ON [PRIMARY] INSERT INTO [RoadBuffer] (Id,GeomData) SELECT OBJECTID AS Id, SHAPE.STBuffer(50) FROM dbo.Road_cl ORDER BY OBJECTID
You can of course write newly generated features into a geodatabase feature class, not just a SQL Server database table. You need to create a new polygon feature class and then run the SQL below. This will create buffer zones for every line found in the Road_cl feature class.
DELETE FROM FC_ROADBUFFERS INSERT INTO FC_ROADBUFFERS(OBJECTID,SHAPE) SELECT OBJECTID AS OBJECTID, SHAPE.STBuffer(50) AS SHAPE FROM dbo.Road_cl ORDER BY OBJECTID
Please refer to the Microsoft Geometry Data Type Method Reference to get a full list of available functions and more detailed description.
Try doing some other analysis such as finding what features intersect or overlap or how many points are located within a certain polygon. There is so much you can do! To learn more, get a book Beginning Spatial with SQL Server 2008 which has tons of examples and will also help you understand the spatial data structure basics. I have read this book and really liked it. I think it is a must read for anyone using spatial SQL.
I hope this short introduction into what you as a GIS user can do with SQL Server will help you take advantage of using the native SQL functions wherever using a desktop GIS is not an option.