Encuentra puntos dentro de una distancia usando MySQL

20

Tengo una tabla mySQL con nombre de usuario, latitud y longitud del usuario. Me gustaría obtener una lista de usuarios que están dentro del círculo o cuadrado de una latitud y longitud dada con una distancia dada. Por ejemplo, mi entrada Lat = 78.3232 y Long = 65.3234 y distancia = 30 millas. Me gustaría obtener la lista de usuarios que están dentro de 30 millas de distancia del punto 78.3232 y 65.3234. ¿Es posible resolver esto con una sola consulta? ¿O puede darme una pista para comenzar a resolver esta consulta? Soy nuevo en la información basada en geo.

shihab K
fuente
¿Por qué no PostGIS? Si está comenzando un proyecto geográfico, aún puede cambiar su pila
simplexio
stackoverflow.com/a/40272394/1281385 Debería ser útil para acelerar esta consulta (si es necesario)
exussum

Respuestas:

32

La instrucción SQL que encontrará las 20 ubicaciones más cercanas dentro de un radio de 30 millas a la coordenada 78.3232, 65.3234. Calcula la distancia en función de la latitud / longitud de esa fila y la latitud / longitud objetivo, y luego solicita solo filas donde el valor de la distancia es inferior a 30 millas, ordena la consulta completa por distancia y la limita a 20 resultados. Para buscar por kilómetros en lugar de millas, reemplace 3959 con 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;

Esto está utilizando la API de Google Maps v3 con un servidor MySQL que ya tienes.

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

Mapperz
fuente
Recibo un error de sintaxis en mi selección usando esto, "# 1582 - Conteo de parámetros incorrecto en la llamada a la función nativa 'radianes', ¿qué podría ser?
Bluantinoo
Encontrado: ¡Tenía la variable lng vacía! ¡lo siento!
bluantinoo
Exactamente lo que quería, pero ¿cuál es la sobrecarga del rendimiento de la consulta para miles de registros? ¿Y qué hay de la precisión?
Amit Shah
1
mucho mejor reemplazarlo a 6371392.896 para buscar por metros
Vasilii Suricov
34

La respuesta de Mapperz no es válida. El seno debe calcularse a partir de la latitud y NO a partir de la longitud. Entonces, la declaración corect SQL es:

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;
Marek Čačko
fuente
Su respuesta debe ser ordenada primero.
Amit Shah
@AmitShah Si cree que podría hacer ping al autor de la pregunta (@shihabK que no ha estado activo en el sitio durante casi 6 años) y / o votar por meta.stackexchange.com/questions/268666/…
PolyGeo
Esta debería ser la respuesta aceptada.
catbadger
2

Puede ser base para crear una función ... para que pueda reutilizarla en otras áreas. También haría su consulta un poco más limpia ... Al menos eso son mis 2 centavos.

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
eDriven_Levar
fuente
la respuesta será votada si arreglas el estilo de código. es la manera correcta
Vasilii Suricov
0

Aquí está mi variante de consulta, parece un poco más fácil ( 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`
dexxtr
fuente
44
Es más fácil pero ignora el hecho de que la tierra es curva.
Tim Rijavec
Necesita una fórmula para ser precisa. Tal vez esto sería bueno solo en distancias cortas: D
Jethro
¿Vas a lanzar un misil o algo así?
Dennis Braga
1
@DennisBraga: si es así, ¿tal vez esta pregunta esté fuera de tema, más adecuada para http://globalthermonuclearwar.stackexchange.com ...?
Ashleedawg