Тип данных географии SQL Server ближайшая точка в строке

Я пытаюсь создать запрос, но у меня есть некоторые трудности.

У меня есть база данных SQL Server 2008 с таблицей, которая включает в себя, среди других полей, поле географии, которое описывает сегменты дороги. (Эти данные были импортированы из данных TIGER/Line из переписи населения США.)

У меня есть другая фиксированная точка, описывающая местоположение пользователя. Я хочу найти ближайший сегмент дороги в базе данных к этому моменту, но я не могу понять, как это сделать. Кроме того, я хочу найти ближайшую точку на этом сегменте к точке местоположения пользователя. Это то, что я хочу выбрать и вернуться в свой запрос.

Есть ли у кого-нибудь опыт работы с географической/геометрической функциональностью, которая может мне помочь?

Спасибо!

Ответ 1

Вы можете сохранить свои объекты в столбце GEOGRAPHY и создать SPATIAL INDEX над этим столбцом.

К сожалению, SQL Server реализует пространственные индексы, разбивая поверхность и сохраняя идентификаторы плитки в обычном индексе B-Tree, поэтому обычный ORDER BY STDistance не будет работать (ну, он будет работать, но не будет использовать индекс).

Вместо этого вам нужно будет сделать запрос, похожий на этот:

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

Таким образом, SQL Server будет сначала искать дороги в пределах 1 километра от вашей точки, затем в пределах 2 километров и т.д., каждый раз, используя индекс.

Update:

Если у вас несколько точек в таблице и вы хотите найти ближайшую точку для каждого из них:

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