J'ai un script PHP fonctionnel qui obtient les valeurs de longitude et de latitude, puis les saisit dans une requête MySQL. Je voudrais en faire uniquement MySQL. Voici mon code PHP actuel:
if ($distance != "Any" && $customer_zip != "") { //get the great circle distance
//get the origin zip code info
$zip_sql = "SELECT * FROM zip_code WHERE zip_code = '$customer_zip'";
$result = mysql_query($zip_sql);
$row = mysql_fetch_array($result);
$origin_lat = $row['lat'];
$origin_lon = $row['lon'];
//get the range
$lat_range = $distance/69.172;
$lon_range = abs($distance/(cos($details[0]) * 69.172));
$min_lat = number_format($origin_lat - $lat_range, "4", ".", "");
$max_lat = number_format($origin_lat + $lat_range, "4", ".", "");
$min_lon = number_format($origin_lon - $lon_range, "4", ".", "");
$max_lon = number_format($origin_lon + $lon_range, "4", ".", "");
$sql .= "lat BETWEEN '$min_lat' AND '$max_lat' AND lon BETWEEN '$min_lon' AND '$max_lon' AND ";
}
Est-ce que quelqu'un sait comment faire cela entièrement MySQL? J'ai un peu navigué sur Internet, mais la plupart de la littérature à ce sujet est assez déroutante.
php
mysql
great-circle
Nick Woodhams
la source
la source
Réponses:
De Google Code FAQ - Création d'un localisateur de magasin avec PHP, MySQL et Google Maps :
la source
markers
table avec des champs id, lan et lng.$greatCircleDistance = acos( cos($latitude0) * cos($latitude1) * cos($longitude0 - $longitude1) + sin($latitude0) * sin($latitude1));
avec latitude et longitude en radian.
alors
est votre requête SQL
pour obtenir vos résultats en Km ou miles, multipliez le résultat par le rayon moyen de la Terre (
3959
miles,6371
Km ou3440
miles nautiques)La chose que vous calculez dans votre exemple est une boîte englobante. Si vous placez vos données de coordonnées dans une colonne MySQL à activation spatiale , vous pouvez utiliser la fonctionnalité intégrée de MySQL pour interroger les données.
la source
Si vous ajoutez des champs d'assistance à la table de coordonnées, vous pouvez améliorer le temps de réponse de la requête.
Comme ça:
Si vous utilisez TokuDB, vous obtiendrez des performances encore meilleures si vous ajoutez des index de clustering sur l'un des prédicats, par exemple, comme ceci:
Vous aurez besoin des lat et lon de base en degrés ainsi que sin (lat) en radians, cos (lat) * cos (lon) en radians et cos (lat) * sin (lon) en radians pour chaque point. Ensuite, vous créez une fonction mysql, comme ceci:
Cela vous donne la distance.
N'oubliez pas d'ajouter un index sur lat / lon pour que la boîte englobante puisse aider la recherche au lieu de la ralentir (l'index est déjà ajouté dans la requête CREATE TABLE ci-dessus).
Étant donné une ancienne table avec uniquement des coordonnées lat / lon, vous pouvez configurer un script pour le mettre à jour comme ceci: (php en utilisant meekrodb)
Ensuite, vous optimisez la requête réelle pour ne faire le calcul de la distance que lorsque cela est vraiment nécessaire, par exemple en délimitant le cercle (enfin, ovale) de l'intérieur et de l'extérieur. Pour cela, vous devrez précalculer plusieurs métriques pour la requête elle-même:
Compte tenu de ces préparatifs, la requête ressemble à ceci (php):
EXPLAIN sur la requête ci-dessus peut indiquer qu'il n'utilise pas d'index à moins qu'il n'y ait suffisamment de résultats pour déclencher un tel. L'index sera utilisé lorsqu'il y aura suffisamment de données dans la table de coordonnées. Vous pouvez ajouter FORCE INDEX (lat_lon_idx) au SELECT pour lui faire utiliser l'index sans tenir compte de la taille de la table, afin que vous puissiez vérifier avec EXPLAIN qu'il fonctionne correctement.
Avec les exemples de code ci-dessus, vous devriez avoir une implémentation fonctionnelle et évolutive de la recherche d'objets par distance avec une erreur minimale.
la source
J'ai dû régler cela en détail, je vais donc partager mon résultat. Cela utilise une
zip
table aveclatitude
etlongitude
tables. Cela ne dépend pas de Google Maps; vous pouvez plutôt l'adapter à n'importe quelle table contenant lat / long.Regardez cette ligne au milieu de cette requête:
Ceci recherche les 30 entrées les plus proches dans le
zip
tableau à moins de 50,0 miles du point lat / long 42,81 / -70,81. Lorsque vous intégrez cela dans une application, c'est là que vous mettez votre propre point et rayon de recherche.Si vous souhaitez travailler en kilomètres plutôt qu'en miles, passez
69
à111.045
et changez3963.17
en6378.10
dans la requête.Voici un résumé détaillé. J'espère que cela aide quelqu'un. http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
la source
J'ai écrit une procédure qui peut calculer la même chose, mais vous devez entrer la latitude et la longitude dans le tableau respectif.
la source
Je ne peux pas commenter la réponse ci-dessus, mais soyez prudent avec la réponse de @Pavel Chuchuva. Cette formule ne retournera pas de résultat si les deux coordonnées sont identiques. Dans ce cas, la distance est nulle et cette ligne ne sera donc pas renvoyée avec cette formule telle quelle.
Je ne suis pas un expert MySQL, mais cela semble fonctionner pour moi:
la source
ACOS(1)
0). Vous pourriez voir des problèmes d'arrondi avec les xaxis * xaxis + yaxis * yaxis + zaxis * zaxis hors de portée pour ACOS, mais vous ne semblez pas vous prémunir contre cela?pour une distance de 25 km
la source
Je pensais que mon implémentation javascript serait une bonne référence à:
la source
calculer la distance en Mysql
ainsi la valeur de distance sera calculée et n'importe qui peut postuler si nécessaire.
la source