2014-02-10 3 views
5

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

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

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

Update [Вещи] установите [Location] = геометрия :: Point (@X, @Y, 0)

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

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

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

UPDATE

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

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

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), 
) 

ответ

9

Это невероятно поздний ответ, но, возможно, я смогу пролить свет на решение.Номер «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() принимает пространственную точку и создает круг (теперь типа Polygon) от него. Вы можете запросить данные, установленные следующим образом:

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

выше теперь будет использовать любой индекс Spatial, который вы создали на [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 недели после того, как вы задали вопрос. Извините, я не видел этого раньше, если бы на вопросы был только один пространственный тег !!!!

+1

Интересное второе решение, мне нужно немного поиграть и подумать об этом. Два незначительных момента: я уверен, что, если вы не работаете на изогнутой поверхности, вы не хотите использовать GEOGRAPHY 4326, которая является неевклидовой поверхностью. Это проблема с плоским пространством, поэтому использование GEOMETRY, вероятно, является правильным выбором. Во-вторых, в вашем примере вы предлагаете использовать таблицу sql temp, когда было бы намного лучше (быстрее) использовать переменную таблицы. Таблицы Temp записывают на диск, в памяти хранятся таблицы vars. – MadTigger

+0

@MadTigger Я не мог больше согласиться на использование переменных таблицы, но если честно, я не тратил времени на оптимизацию, а больше теорию, чтобы помочь вам на вашем пути - учитывая, что уже 4 недели у вас уже есть решил! :-) Простите предположение на 4326, опять же, если вы работаете над проблемой с плоским пространством, вы совершенно правы, чтобы не использовать 4326 и использовать Geometry. Я просто привык к людям, использующим Geometry, как копункт для реальных проблем с «Землей», когда они должны использовать Географию, и ваш вопрос был неясным в этом отношении. Предполагаемая привычка - это то, что я должен пинать. –

-1

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

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 

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

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 
+0

Так вы бы это сделали, если бы собираетесь использовать базовые типы данных SQL. Тем не менее, я прошу об использовании объектов геометрии SQL, особенно потому, что они используют квадранты или другое пространственное индексирование. Ваше решение будет полностью отделено друг от друга, если вы захотите выполнить поиск db, на котором было несколько сотен тысяч точек, где объект, который использует пространственное разбиение, не будет иметь никаких проблем. С вашим решением становится еще хуже, поскольку я добавляю дополнительные лучи, так как мне нужно было бы проверить расстояние до каждой точки в db для каждого радиуса, на который я собирался посмотреть. Спасибо за попытку, хотя – MadTigger

+0

Сервер не волшебный, вы все равно будете делать огромное количество вычислений. Вам понадобится хранилище данных или вычисленное поле, если это огромные таблицы, а загрузка или время работы сервера важны. Тем не менее, решение обновлено, чтобы содержать возможность SQL-Native. –

+1

Неправильное. Точка пространственного индексирования (деревья BSP, квадранты и т. Д.) Состоит в том, чтобы избежать необходимости выполнять всю математику, быстро сокращая пространство поиска до соответствующих данных. Spacial indexing, когда правильно используется, очень, очень быстро. Как говорится, ссылки, которые вы нашли, были очень полезными. Я собираюсь написать и опубликовать краткое описание того, как это сделать для будущих читателей. Спасибо за помощь. – MadTigger

Смежные вопросы