Похоже, есть расширение для Express C, которое включает в себя пространственную обработку. Я никогда не использовал его (и, кажется, не могу получить доступ в данный момент), поэтому я не могу говорить с ним. Я предполагаю, что вы захотите использовать это (найти все местоположения в радиусе - довольно стандартный запрос).
Если по какой-то причине вы не можете использовать расширение, вот что я бы сделал:
Сохраняйте свою таблицу как есть, или, возможно, используйте тип данных с плавающей точкой, хотя, пожалуйста, используйте полные имена атрибутов (нет причин для их усечения). Для простых нужд имя «местоположения» может быть сохранено в таблице, но вы можете присвоить ему числовой идентификатор, если в одном и том же месте находятся несколько предметов (поэтому фактические точки присутствуют там только один раз).
Вам также понадобятся индикаторы, покрывающие широту и долготу (вероятно, по одному в каждом направлении или по одному на каждый столбец).
Затем, учитывая начальную позицию и расстояние, используйте этот запрос:
SELECT name, latitude, longitude
FROM location
WHERE (latitude >= :currentLatitude - :distance
AND latitude <= :currentLatitude + :distance)
AND (longitude >= :currentLongitude - :distance
AND longitude <= :currentLongitude + :distance)
-- The previous four lines reduce the points selected to a box.
-- This is, or course, not completely correct, but should allow
-- the query to use the indicies to greatly reduce the initial
-- set of points evaluated.
-- You may wish to flip the condition and use ABS(), but
-- I don't think that would use the index...
AND POWER(latitude - :currentLatitude, 2) + POWER(longitude - :currentLongitude, 2)
<= POWER (:distance, 2)
-- This uses the pythagorean theorem to find all points within the specified
-- distance. This works best if the points have been pre-limited in some
-- way, because an index would almost certainly not be used otherwise.
-- Note that, on a spherical surface, this isn't completely accurate
-- - namely, distances between longitude points get shorter the farther
-- from the equator the latitude is -
-- but for your purposes is likely to be fine.
<ч />
РЕДАКТИРОВАТЬ:
Обнаружил это после поиска в течение 2 секунд в Google , который также напомнил мне, что :distance
будет в неправильных единицах. Пересмотренный запрос:
WITH Nearby (name, latitude, longitude, dist) as (
SELECT name, latitdude, longitude,
ACOS(SIN(RADIANS(latitude)) * SIN(RADIANS(:currentLatitude)) +
COS(RADIANS(latitude)) * COS(RADIANS(:currentLatitude)) *
COS(RADIANS(:currentLongitude - longitude))) * :RADIUS_OF_EARTH as dist
FROM location
WHERE (latitude >= :currentLatitude - DEGREES(:distance / :RADIUS_OF_EARTH)
AND latitude <= :currentLatitude + DEGREES(:distance / :RADIUS_OF_EARTH))
AND (longitude >= :currentLongitude -
DEGREES(:distance / :RADIUS_OF_EARTH / COS(RADIANS(:currentLatitude)))
AND longitude <= :currentLongitude +
DEGREES(:distance / :RADIUS_OF_EARTH / COS(RADIANS(:currentLatitude))))
)
SELECT *
FROM Nearby
WHERE dist <= :distance
Обратите внимание, что перенос функции расстояния в UDF, помеченный DETERMINISTIC
, позволил бы поместить ее как в части SELECT
, так и HAVING
, но на самом деле вызывать только один раз , исключая нужен для CTE.