SQL-запрос, выберите ближайшие места по заданным координатам

У меня $latitude = 29.6815400 и $longitude = 64.3647100 , теперь в MySQL я хотел бы взять 15 ближайших мест в эти координаты, и я планирую сделать этот запрос:

 SELECT * FROM places WHERE latitude BETWEEN($latitude - 1, $latitude + 1) AND longitude BETWEEN($longitude - 1, $logintude + 1) LIMIT 15; 

Вы считаете, что это правильно или вы предлагаете что-то еще?

Как сделать BEETWEEN , так как я хочу искать в пределах до 50 км диапазона ближайших мест?

Я забыл сказать, что я также могу использовать PHP для выполнения чего-либо прежде, чем запускать запрос.

Примечание. Я не могу использовать хранимые процедуры .

вот формула PHP для вычисления расстояния между двумя точками :

 function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'Mi') { $theta = $longitude1 - $longitude2; $distance = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))+ (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta))); $distance = acos($distance); $distance = rad2deg($distance); $distance = $distance * 60 * 1.1515; switch($unit) { case 'Mi': break; case 'Km' : $distance = $distance * 1.609344; } return (round($distance,2)); } 

затем добавьте запрос, чтобы получить все записи с расстоянием, меньшим или равным указанному выше:

 $qry = "SELECT * FROM (SELECT *, (((acos(sin((".$latitude."*pi()/180)) * sin((`geo_latitude`*pi()/180))+cos((".$latitude."*pi()/180)) * cos((`geo_latitude`*pi()/180)) * cos(((".$longitude."- `geo_longitude`)*pi()/180))))*180/pi())*60*1.1515*1.609344) as distance FROM `ci_geo`)myTable WHERE distance <= ".$distance." LIMIT 15"; 

и вы можете посмотреть здесь для подобных вычислений.

и вы можете прочитать больше здесь

Обновить:

вы должны учитывать, что для вычисления longitude2 и longitude2 вам нужно знать, что:

Каждая градус широты составляет приблизительно 69 миль (111 километров) друг от друга. Диапазон варьируется (из-за слегка эллипсоидной формы земли) от 68,703 миль (110,567 км) на экваторе до 69,407 (111,699 км) на полюсах. Это удобно, потому что каждая минута (1/60 градуса) составляет примерно одну милю.

Степень долготы наиболее широка на экваторе на 69,172 миль (111,321) и постепенно сжимается до нуля на полюсах. На 40 ° севернее или юг расстояние между степенью долготы составляет 53 мили (85 км).

поэтому рассчитать $longitude2 $latitude2 соответствии с 50 км, а затем примерно:

 $longitude2 = $longitude1 + 0.449; //0.449 = 50km/111.321km $latitude2 = $latitude1 + 0.450; // 0.450 = 50km/111km 

Вы должны учитывать, что наводнение любых СУБД, таких как MySQL с тяжелыми запросами никогда не должно быть хорошим решением .

Вместо этого вы можете спроектировать очень быстрый SQL-запрос, который выбирает все места с координатами внутри простого квадрата бокового $radius , вместо того, чтобы точно выбирать идеальный радиус круга. PHP может фильтровать излишки.

Позвольте мне показать простую концепцию:

 $lat = 45.0.6072; $lon = 7.65678; $radius = 50; // Km $angle_radius = $radius / 111; // Every lat|lon degree° is ~ 111Km $min_lat = $lat - $angle_radius; $max_lat = $lat + $angle_radius; $min_lon = $lon - $angle_radius; $max_lon = $lon + $angle_radius; $results = $db->get_results("... WHERE latitude BETWEEN $min_lat AND $max_lat AND longitude BETWEEN $min_lon AND $max_lon"); // A own function that return an array full with all the results rows $n_rows = count($results); for($i=0; $i<$n_rows; $i++) { if(getDistanceBetweenPointsNew($lat, $lon, $results[$i]->latitude, $results[$i]->longitude, 'Km') > $radius) { // This is out of the "perfect" circle radious. Strip it out. unset($results[$i]); } } // Now do something with your result set var_dump($results); не $lat = 45.0.6072; $lon = 7.65678; $radius = 50; // Km $angle_radius = $radius / 111; // Every lat|lon degree° is ~ 111Km $min_lat = $lat - $angle_radius; $max_lat = $lat + $angle_radius; $min_lon = $lon - $angle_radius; $max_lon = $lon + $angle_radius; $results = $db->get_results("... WHERE latitude BETWEEN $min_lat AND $max_lat AND longitude BETWEEN $min_lon AND $max_lon"); // A own function that return an array full with all the results rows $n_rows = count($results); for($i=0; $i<$n_rows; $i++) { if(getDistanceBetweenPointsNew($lat, $lon, $results[$i]->latitude, $results[$i]->longitude, 'Km') > $radius) { // This is out of the "perfect" circle radious. Strip it out. unset($results[$i]); } } // Now do something with your result set var_dump($results); 

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

Счастливый взлом!

Я сделал что-то подобное с приложением для продажи дома, заказывая расстояние от заданной точки, поместите это в свой оператор select SQL:

 ((ACOS(SIN(' . **$search_location['lat']** . ' * PI() / 180) * SIN(**map_lat** * PI() / 180) + COS(' . **$search_location['lat']** . ' * PI() / 180) * COS(**map_lat** * PI() / 180) * COS((' . **$search_location['lng']** . ' - **map_lng**) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS "distance" 

Замените $search_location вашими соответствующими значениями lat / lng, а значения map_lat / map_lng – это столбцы SQL, которые содержат значения lat / lng. Затем вы можете упорядочить результаты по расстоянию и использовать опцию where или having для фильтрации наших свойств в диапазоне 50 км.

Я бы рекомендовал использовать SQL в качестве подхода по сравнению с PHP, если вам нужны дополнительные функции, такие как пейджинг.

Немного поздно, но это может помочь кому-то – если вы хотите, чтобы ближайший город по местоположению, я бы не пошел на расстояние, потому что тогда изолированное место ничего не извлекло бы. Попробуй это:

 $G_how_close_to_find_cities = "1.1"; // eg 1.1 = 10% , 1.2=20% etc $G_how_many_cities_to_find_by_coordinates = "10"; $query = "SELECT * from Cities WHERE Cities__Latitude <= ('".$latitude*$G_how_close_to_find_cities."') AND Cities__Latitude >= ('".$latitude/$G_how_close_to_find_cities."') AND Cities__Longitude <= ('".$longitude*$G_how_close_to_find_cities."') AND Cities__Longitude >= ('".$longitude/$G_how_close_to_find_cities."') ORDER BY SQRT(POWER((Cities__Latitude - ".$latitude."),2)+POWER((Cities__Longitude - ".$longitude."),2)) LIMIT 0,".$G_how_many_cities_to_find_by_coordinates;