SQL query, выберите ближайшие места по заданным координатам [дубликат]
этот вопрос уже есть ответ здесь:
Я $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 для чего-либо, прежде чем запускать запрос.
Примечание: я не могу использовать хранимые процедуры.
4 ответов
здесь 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 градуса) составляет примерно одну милю.
степень долгота is самый широкий на экваторе при 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
, вместо того, чтобы выбрать suddently идеальный радиус круга. PHP
может фильтровать излишки.
позвольте мне показать простую концепцию:
$lat = 45.0.6072;
$lon = 7.65678;
$radius = 50; // Km
$angle_radius = $radius / ( 111 * cos( $lat ) ); // 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 radius. Strip it out.
unset($results[$i]);
}
}
// Now do something with your result set
var_dump($results);
так MySQL
выполняет очень дружественный запрос, который не требует прочитайте весь набор баз данных и PHP
удаляет излишек с чем-то похожим на getDistanceBetweenPointsNew()
функция размещена на этой странице, сравнивая расстояние от координат результирующего набора до центра вашего радиуса.
чтобы не тратить (большой) прирост производительности, индексируйте столбцы координат в базе данных.
всего доброго!
Я сделал что-то подобное с приложением продажи домов, заказывая по расстоянию от заданной точки, поместите это в свой оператор SQL select:
((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"; // e.g. 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;