Геометрия SQL найти все точки в радиусе
Я свободно владею SQL, но новичок в использовании функций геометрии SQL. У меня есть, вероятно, очень основная проблема для решения, но я не нашел хороших ресурсов в интернете, которые объясняют, как использовать объекты геометрии. (Technet-паршивый способ узнать что-то новое...)
у меня есть коллекция 2D точек на декартовой плоскости, и я пытаюсь найти все точки, которые находятся в коллекции радиусов.
Я создал и заполнил таблицу с помощью синтаксиса например:
Update [Things] set [Location] = геометрия:: точка (@X, @Y, 0)
(@X,@Y - это только значения x и y, 0-произвольное число, разделяемое всеми объектами, которое позволяет установить фильтрацию, если я правильно понимаю)
вот где я сойду с рельсов...я пытаюсь построить какую-то коллекцию полигонов и запрос, используя это, или есть какой-то простой способ проверки пересечения нескольких радиусов без создания связки круговых полигоны?
добавление: если ни у кого нет ответа на вопрос о нескольких радиусах, что такое решение с одним радиусом?
обновление
вот несколько примеров, которые я разработал, используя воображаемую звездную базу данных, где звезды хранятся на сетке x-y как точки:
выбирает все точки в окно:
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
INSERT [Star]
(
[Name],
[StarTypeId],
[Location],
)
VALUES
(
@GameId,
@Name,
@StarTypeId,
GEOMETRY::Point(@LocationX, @LocationY, 0),
)
2 ответов
Это невероятно поздний ответ, но возможно, я смогу пролить свет на решение. Номер "set", на который вы ссылаетесь, является Индентификатором пространственной привязки или SRID. Для расчетов lat / long следует установить значение 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 () берет пространственную точку и создает из нее круг (Теперь многоугольник). Затем вы можете запросить свой набор данных следующим образом:
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% уверен, что это просто там с небольшим количеством настроек, являющихся возможностью. Идеал принимать минимальное расстояние радиуса в отборе что если несколько радиусов происходят из одного места, если точка находится в пределах первого радиуса, она, естественно, будет во всех остальных. Поэтому вы будете дублировать запись, но, группируя и выбирая min, вы получаете только одну (и ближайшую).
надеюсь, что это поможет, хотя через 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