Найти точки на расстоянии, используя MySQL


20

У меня есть таблица MySQL с именем пользователя, широтой и долготой пользователя. Я хотел бы получить список пользователей, которые находятся внутри круга или квадрата заданной широты и долготы с заданным расстоянием. Например, мой ввод Lat = 78.3232 и Long = 65.3234 и расстояние = 30 миль. Я хотел бы получить список пользователей, которые находятся на расстоянии 30 миль от точек 78.3232 и 65.3234. Можно ли решить это одним запросом? Или вы можете дать мне подсказку начать решение этого запроса? Я новичок в гео информации.


Почему не PostGIS? Если вы начинаете гео-проект, вы все равно можете изменить свой стек
simplexio

stackoverflow.com/a/40272394/1281385 Должно быть полезно для ускорения этого запроса (при необходимости)
exussum

Ответы:


32

Оператор SQL, который найдет ближайшие 20 местоположений в радиусе 30 миль от координаты 78.3232, 65.3234. Он вычисляет расстояние на основе широты / долготы этой строки и целевой широты / долготы, а затем запрашивает только те строки, в которых значение расстояния меньше 30 миль, упорядочивает весь запрос по расстоянию и ограничивает его 20 результатами. Для поиска по километрам вместо миль замените 3959 на 6371.

SELECT
  id, (
    3959 * acos (
      cos ( radians(78.3232) )
      * cos( radians( lat ) )
      * cos( radians( lng ) - radians(65.3234) )
      + sin ( radians(78.3232) )
      * sin( radians( lat ) )
    )
  ) AS distance
FROM markers
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 20;

Это использует API Карт Google v3 с бэкэндом MySQL, который у вас уже есть.

https://developers.google.com/maps/articles/phpsqlsearch_v3#findnearsql


Я получаю синтаксическую ошибку в моем выборе, используя это, "# 1582 - Неправильный счетчик параметров в вызове нативной функции 'радианы', что это могло быть?
bluantinoo

Найдено: у меня переменная lng пуста! извиняюсь!
Bluantinoo

Именно то, что я хотел, но какова перегрузка производительности запросов для тысяч записей? а как насчет точности?
Амит Шах

1
гораздо лучше заменить его на 6371392.896 для поиска по счетчикам
Василий Суриков

34

Mapperz ответ неверен. Синус должен быть рассчитан по широте, а не по долготе. Итак, SQL-оператор corect:

SELECT
    id, (
      3959 * acos (
      cos ( radians(78.3232) )
      * cos( radians( lat ) )
      * cos( radians( lng ) - radians(65.3234) )
      + sin ( radians(78.3232) )
      * sin( radians( lat ) )
    )
) AS distance
FROM markers
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 20;

Ваш ответ должен быть заказан 1-й.
Амит Шах

@AmitShah Если вы думаете, что можете пропинговать спрашивающего (@shihabK, который не был активен на сайте в течение почти 6 лет) и / или голосовать за meta.stackexchange.com/questions/268666/…
PolyGeo

Это должен быть принятый ответ.
catbadger

2

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

DELIMITER $$

create function calcDistance(lat float, lng float, pnt_lat float, pnt_lng float)

Returns float
BEGIN

Declare dist float;
SET dist =
  3959 * acos (
  cos ( radians(pnt_lat) )
  * cos( radians( lat ) )
  * cos( radians( lng ) - radians(pnt_lng) )
  + sin ( radians(pnt_lat) )
  * sin( radians( lat ) )
);

RETURN dist;

END

Ответ будет отклонен, если вы исправите стиль кода. это правильный путь
Василий Суриков

0

Вот мой вариант запроса, кажется немного проще ( http://dexxtr.com/post/83498801191/how-to-determine-point-inside-circle-using-mysql )

SELECT 
    *
FROM 
    `locator`
WHERE
    SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`

4
Это проще, но игнорирует тот факт, что земля изогнута.
Тим Риявец

Нужна формула, чтобы быть точным. Может быть, это будет хорошо только на коротких дистанциях: D
Jethro

Я собираюсь запустить ракету, или что-то?
Деннис Брага

1
@DennisBraga - если так, то, возможно, этот вопрос не по теме, лучше подходит для http://globalthermonuclearwar.stackexchange.com ...?
ashleedawg
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.