Trouver des points à distance en utilisant MySQL

20

J'ai une table mySQL avec le nom d'utilisateur, la latitude et la longitude de l'utilisateur. Je voudrais obtenir une liste d'utilisateurs qui sont à l'intérieur du cercle ou du carré d'une latitude et d'une longitude données avec une distance donnée. Par exemple, mon entrée Lat = 78,3232 et Long = 65,3234 et la distance = 30 miles. Je voudrais obtenir la liste des utilisateurs qui se trouvent à moins de 30 miles du point 78.3232 et 65.3234. Est-il possible de résoudre ce problème avec une seule requête? Ou pouvez-vous me donner un indice pour commencer à résoudre cette requête? Je suis nouveau dans les informations géo-basées.

shihab K
la source
Pourquoi pas PostGIS? Si vous démarrez un projet géo, vous pouvez toujours changer votre pile
simplexio
stackoverflow.com/a/40272394/1281385 Devrait être utile pour accélérer cette requête (si nécessaire)
Exussum

Réponses:

32

L'instruction SQL qui trouvera les 20 emplacements les plus proches dans un rayon de 30 miles par rapport aux coordonnées 78,3232, 65,3234. Il calcule la distance en fonction de la latitude / longitude de cette ligne et de la latitude / longitude cible, puis demande uniquement les lignes dont la valeur de distance est inférieure à 30 miles, ordonne la requête entière par distance et la limite à 20 résultats. Pour rechercher par kilomètres au lieu de miles, remplacez 3959 par 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;

Cela utilise l'API Google Maps v3 avec un backend MySQL que vous avez déjà.

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

Mapperz
la source
J'obtiens une erreur de syntaxe dans ma sélection en utilisant ceci, "# 1582 - Nombre de paramètres incorrect dans l'appel à la fonction native" radians "qu'est-ce que cela pourrait être?
bluantinoo
Trouvé: j'avais la variable lng vide! Pardon!
bluantinoo
Exactement ce que je voulais, mais quelle est la surcharge de performances des requêtes pour des milliers d'enregistrements? et qu'en est-il de la précision?
Amit Shah
1
beaucoup mieux pour le remplacer au 6371392.896 pour la recherche par mètres
Vasilii Suricov
34

La réponse de Mapperz n'est pas valide. Le sinus doit être calculé à partir de la latitude et NON à partir de la longitude. Donc, l'instruction SQL corect est:

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
la source
Votre réponse doit être commandée en premier.
Amit Shah
@AmitShah Si vous pensez que vous pourriez cingler le demandeur (@shihabK qui n'a pas été actif sur le site depuis près de 6 ans) et / ou voter pour meta.stackexchange.com/questions/268666/…
PolyGeo
Ce devrait être la réponse acceptée.
catbadger
2

Il peut être utile de créer une fonction. Vous pouvez donc la réutiliser dans d'autres domaines. Cela rendrait également votre requête un peu plus propre ... Au moins, c'est mes 2 cents.

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
la source
la réponse sera votée si vous corrigez le codestyle. c'est le bon chemin
Vasilii Suricov
0

Voici ma variante de requête, semble un peu plus facile ( 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
la source
4
C'est plus facile mais ignore le fait que la terre est courbée.
Tim Rijavec
Besoin d'une formule pour être précis. Peut-être que ce ne serait bon que sur de courtes distances: D
Jethro
Tu vas lancer un missile, ou quelque chose?
Dennis Braga
1
@DennisBraga - si oui, alors peut-être que cette question est hors sujet, mieux adaptée à http://globalthermonuclearwar.stackexchange.com ...?
ashleedawg