SQL геометрия найти все точки в радиусе

Я свободно владею SQL, но плохо знаком с использованием функций геометрии SQL. У меня есть, пожалуй, одна из основных проблем, которую нужно решить, но я не нашел в сети хороших ресурсов, объясняющих, как использовать геометрические объекты. (Technet - паршивый способ изучать новые вещи...)

У меня есть набор 2d точек на декартовой плоскости, и я пытаюсь найти все точки, которые находятся в пределах набора радиусов.

Я создал и заполнил таблицу, используя синтаксис, такой как:

Обновить [Вещи] установить [Местоположение] = геометрия:: Точка (@X, @Y, 0)

(@ X, @ Y - это просто значения x и y, 0 - произвольное число, общее для всех объектов, которое позволяет установить фильтрацию, если я правильно понимаю)

Вот где я схожу с рельсов... Пытаюсь ли я создать какой-то набор полигонов и запрос, используя это, или есть какой-то простой способ проверки пересечения нескольких радиусов без построения группы круглых многоугольников?

Приложение: Если ни у кого нет ответа на вопрос о нескольких радиусах, каково решение с одним радиусом?

ОБНОВИТЬ

Вот несколько примеров, которые я разработал, используя воображаемую базу данных звезд, где звезды хранятся в сетке xy в виде точек:

Выбирает все точки в окне:

DECLARE @polygon geometry = geometry::STGeomFromText('POLYGON((' 
+ CAST(@MinX AS VARCHAR(10)) + ' '  + CAST(@MinY AS VARCHAR(10)) + ',' 
+ CAST(@MaxX AS VARCHAR(10)) + ' '  + CAST(@MinY AS VARCHAR(10)) + ', ' 
+ CAST(@MaxX AS VARCHAR(10)) + ' '  + CAST(@MaxY AS VARCHAR(10)) + ',' 
+ CAST(@MinX AS VARCHAR(10)) + ' '  + CAST(@MaxY AS VARCHAR(10)) + ',' 
+ CAST(@MinX AS VARCHAR(10)) + ' '  + CAST(@MinY AS VARCHAR(10)) + '))', 0);

SELECT  [Star].[Name]           AS [StarName],
        [Star].[StarTypeId]     AS [StarTypeId],        
FROM    [Star]
WHERE   @polygon.STContains([Star].[Location]) = 1

используя это как шаблон, вы можете делать разные интересные вещи, такие как определение нескольких полигонов:

WHERE   @polygon1.STContains([Star].[Location]) = 1
OR @polygon2.STContains([Star].[Location]) = 1
OR @polygon3.STContains([Star].[Location]) = 1

Или проверка расстояния:

WHERE [Star].[Location].STDistance(@polygon1) < @SomeDistance 

Пример вставки

INSERT [Star]
(
    [Name],
    [StarTypeId],
    [Location],
)
VALUES
(
    @GameId,
    @Name,
    @StarTypeId,
    GEOMETRY::Point(@LocationX, @LocationY, 0),
)

2 ответа

Решение

Это невероятно поздний ответ, но, возможно, я смогу пролить свет на решение. Номер "set", на который вы ссылаетесь, является Идентификатором пространственной привязки или SRID. Для вычислений широты и долготы вы должны установить значение 4326, которое обеспечит использование счетчиков в качестве единицы измерения. Вам также следует подумать о переходе на SqlGeography, а не на SqlGeometry, но сейчас мы продолжим с SqlGeometry. Чтобы массово установить SRID, вы можете обновить таблицу следующим образом:

UPDATE [YourTable] SET [SpatialColumn] = GEOMETRY.STPointFromText([SpatialColumn].STAsText(), 4326);

Для одного радиуса вам нужно создать радиусы как пространственный объект. Например:

DECLARE @radiusInMeters FLOAT = 1000; -- Set to a number in meters
DECLARE @radius GEOMETRY = GEOMETRY::Point(@x, @y, 4326).STBuffer(@radiusInMeters);

STBuffer () берет пространственную точку и создает из нее окружность (теперь тип Polygon). Затем вы можете запросить ваш набор данных следующим образом:

SELECT * FROM [YourTable] WHERE [SpatialColumn].STIntersects(@radius);

Выше теперь будет использовать любой пространственный индекс, который вы создали на [SpatialColumn] в своем плане запросов.

Существует также более простой вариант, который будет работать (и при этом использовать пространственный индекс). Метод STDistance позволяет вам делать следующее:

DECLARE @radius GEOMETRY = GEOMETRY::Point(@x, @y, 4326);
DECLARE @distance FLOAT = 1000; -- A distance in metres   
SELECT * FROM [YourTable] WHERE [SpatialColumn].STDistance(@radius) <= @distance;

Наконец, работа с коллекцией радиусов. У вас есть несколько вариантов. Во-первых, нужно запустить приведенное выше для каждого радиуса по очереди, но я хотел бы рассмотреть следующее, чтобы сделать это как один:

DECLARE #radiiCollection TABLE
(
    [RadiusInMetres] FLOAT,
    [Radius] GEOMETRY
)

INSERT INTO #radiiCollection ([RadiusInMetres], [Radius]) VALUES (1000, GEOMETRY::Point(@xValue, @yValue, 4326).STBuffer(1000));
-- Repeat for other radii

SELECT
    X.[Id],
    MIN(R.[RadiusInMetres]) AS [WithinRadiusDistance]
FROM
    [YourTable] X
    JOIN
    #radiiCollection RC ON RC.[Radius].STIntersects(X.[SpatialColumn])
GROUP BY
    X.[IdColumn],
    R.[RadiusInMetres]

DROP TABLE @radiiCollection;

Финал выше не был проверен, но я уверен на 99%, что возможна небольшая настройка. Идеал брать минимальное расстояние радиуса в выборке состоит в том, что если несколько радиусов происходят из одного местоположения, если точка находится в пределах первого радиуса, она, естественно, будет в пределах всех остальных. Поэтому вы продублируете запись, но, сгруппировав и выбрав мин, вы получите только одну (и ближайшую).

Надеюсь, это поможет, хотя и через 4 недели после того, как вы задали вопрос. Извините, я не видел этого раньше, если бы был только один пространственный тег для вопросов!!!!

Конечно, это возможно. Индивидуальное выражение where должно быть примерно таким:

DIM @Center AS Location
-- Initialize the location here, you probably know better how to do that than I.
Dim @Radius AS Decimal(10, 2)
SELECT * from pointTable WHERE sqrt(square(@Center.STX-Location.STX)+square(@Center.STX-Location.STX)) > @Radius 

Затем вы можете сложить кучу радиусов и точек xy в табличную переменную, которая выглядит следующим образом:

Dim @MyCircleTable AS Table(Geometry Circle) 
INSERT INTO @MyCircleTable (.........)

Примечание: я не ставил это через компилятор, но это голое рабочее решение.

Другой вариант выглядит здесь: http://technet.microsoft.com/en-us/library/bb933904.aspx

И здесь есть демонстрация вроде бы работающего синтаксиса: http://social.msdn.microsoft.com/Forums/sqlserver/en-US/6e1d7af4-ecc2-4d82-b069-f2517c3276c2/slow-spatial-predicates-stcontains-stintersects-stwithin-?forum=sqlspatial

Второй пост подразумевает синтаксис:

SELECT Distinct pointTable.* from pointTable pt, circletable crcs
WHERE crcs.geom.STContains(b.Location) = 1
Другие вопросы по тегам