Je pense que votre question indique que vous avez la city
valeurs pour les deux villes entre lesquelles vous souhaitez calculer la distance.
Cette requête fera le travail pour vous, donnant la distance en km. Il utilise la formule de la loi du cosinus sphérique.
Notez que vous joignez la table à elle-même afin de pouvoir récupérer deux paires de coordonnées pour le calcul.
SELECT a.city AS from_city, b.city AS to_city,
111.111 *
DEGREES(ACOS(LEAST(1.0, COS(RADIANS(a.Latitude))
* COS(RADIANS(b.Latitude))
* COS(RADIANS(a.Longitude - b.Longitude))
+ SIN(RADIANS(a.Latitude))
* SIN(RADIANS(b.Latitude))))) AS distance_in_km
FROM city AS a
JOIN city AS b ON a.id <> b.id
WHERE a.city = 3 AND b.city = 7
Notez que la constante 111.1111
est le nombre de kilomètres par degré de latitude, basé sur l'ancienne définition napoléonienne du mètre comme un dix-millième de la distance entre l'équateur et le pôle. Cette définition est suffisamment proche pour le travail de localisation.
Si vous voulez des milles terrestres au lieu de kilomètres, utilisez 69.0
à la place.
http://sqlfiddle.com/#!9/21e06/412/0
Si vous recherchez des points à proximité, vous pourriez être tenté d'utiliser une clause comme celle-ci :
HAVING distance_in_km < 10.0 /* slow ! */
ORDER BY distance_in_km DESC
C'est (comme on dit près de Boston MA USA) méchant lent.
Dans ce cas, vous devez utiliser un calcul de boîte englobante. Voir cet article sur la façon de le faire. http://www.plumislandmedia.net/mysql/haversine-mysql- emplacement-le-plus-proche/
La formule contient un LEAST()
une fonction. Pourquoi? Parce que le ACOS()
fonction renvoie une erreur si son argument est même légèrement supérieur à 1. Lorsque les deux points en question sont très proches, l'expression avec le COS()
et SIN()
les calculs peuvent parfois donner une valeur légèrement supérieure à 1 en raison de epsilon à virgule flottante (inexactitude
). Le LEAST(1.0, dirty-great-expression)
appel résout ce problème.
Il existe un meilleur moyen, une formule
par Thaddeus Vincenty
. Il utilise ATAN2()
plutôt que ACOS()
il est donc moins sensible aux problèmes d'epsilon.