I am trying to build a query, but I am having some difficulty.
I have a SQL Server 2008 database with a table that includes, among other fields, a geography field that describes road segments. (This data has been imported from TIGER/Line data from the U.S. Census.)
I have another fixed point describing a user's location. I want to find the closest road segment in the database to that point, but I can't seem to figure out how to accomplish this. Furthermore, I want to find the closest point on that segment to the user location point. This is what I want to select and return back in my query.
Does anyone have any experience with the geography/geometry functionality that can help me?
Thanks!
The connecting edge between two vertices in a geometry type is a straight line. However, the connecting edge between two vertices in a geography type is a short great elliptic arc between the two vertices.
In SQL Server spatial data, a Point is a 0-dimensional object representing a single location and may contain Z (elevation) and M (measure) values.
SQL Server supports two spatial data types: the geometry data type and the geography data type. The geometry type represents data in a Euclidean (flat) coordinate system. The geography type represents data in a round-earth coordinate system.
SQL Server supports spatial data and spatial indexes. A spatial index is a type of extended index that allows you to index a spatial column. A spatial column is a table column that contains data of a spatial data type, such as geometry or geography.
You can store your objects in a GEOGRAPHY
column and create a SPATIAL INDEX
over this column.
Unfortunately, SQL Server
implements spatial indexes by tiling the surface and storing the tile identifiers in a plain B-Tree
index, so plain ORDER BY STDistance
won't work (well, it will work but won't use the index).
Instead, you'll have to make a query similar to this:
DECLARE @mypoint GEOGRAPHY
SET @mypoint = geography::STGeomFromText('POINT(@mylat, @mylon)', 4326);
WITH num (distance) AS
(
SELECT 1000
UNION ALL
SELECT distance + 1000
FROM num
WHERE distance <= 50000
)
SELECT TOP 1 m.*
FROM num
CROSS APPLY
(
SELECT TOP 1 *
FROM mytable
WHERE myroad.STDistance(@mypoint) <= distance
ORDER BY
STDistance(@mypoint)
) m
This way, SQL Server
will first search roads within 1
kilometer from your point, then within 2
kilometers, etc., each time using the index.
Update:
If you have multiple points in a table and want to find the closest point for each of them:
WITH num (distance) AS
(
SELECT 1000
UNION ALL
SELECT distance + 1000
FROM num
WHERE distance <= 50000
)
SELECT mp.mypoint, m.*
FROM @mypoints mp
CROSS APPLY
(
SELECT TOP 1 m.*
FROM num
CROSS APPLY
(
SELECT TOP 1 *
FROM mytable
WHERE myroad.STDistance(@mypoint) <= distance
ORDER BY
STDistance(@mypoint)
) m
) m
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With