Запросы на поиск мест в заданном лат / lng

Поэтому я пытаюсь отобразить списки мест в пределах диапазона данных lat / lng. У меня нет проблем с этим:

Места в пределах одной мили (список мест …)

Используя что-то вроде

SELECT * FROM places WHERE lat < $latmax AND lat > $latmin AND lng < $lngmax AND lng > $lngmin 

Но затем я хочу перечислить места в двух милях, но не в пределах одной мили – то есть, я не хочу повторять результаты первого запроса.

Вот одна из версий того, что я пробовал:

 $milesperdegree = 0.868976242 / 60.0 * 1.2; // 1 mile -- this works $degrees = $milesperdegree * 1; $latmin = $lat - $degrees; $latmax = $lat + $degrees; $lngmin = $lng - $degrees; $lngmax = $lng + $degrees; $query = "SELECT * FROM places WHERE lat < $latmax AND lat > $latmin AND lng < $lngmax AND lng > $lngmin"; // 2 miles -- this doesn't work $degrees_2 = $milesperdegree * 2; $latmin_2 = $lat - $degrees_2; $latmax_2 = $lat + $degrees_2; $lngmin_2 = $lat - $degrees_2; $lngmax_2 = $lat + $degrees_2; $query = "SELECT * FROM places WHERE "; $query .= "lat BETWEEN $latmax AND $latmax_2 AND lng BETWEEN $lngmax AND $lngmax_2 OR "; $query .= "lat BETWEEN $latmin AND $latmin_2 AND lng BETWEEN $lngmin AND $lngmin_2 OR "; $query .= "lat BETWEEN $latmax AND $latmax_2 AND lng BETWEEN $lngmin AND $lngmin_2 OR "; $query .= "lat BETWEEN $latmin AND $latmin_2 AND lng BETWEEN $lngmax AND $lngmax_2"; 

Это не так. Я предполагаю, что это просто логика, которую я не могу окутать в воскресенье днем, но я, вероятно, тоже делаю что-то еще неправильно. Любой вход очень приветствуется.

Мы используем его более или менее как код ниже (отказ от ответственности: я вырезал это из файла и удалил код, который не имел отношения к проблеме. Я не запускал это, но вы должны иметь возможность получить эту идею.

 $maxLat = $city->latitude + ($max_distance / 69); // 69 Miles/Degree $minLat = $city->latitude - ($max_distance / 69); $maxLon = $city->longitude + ($max_distance / (69.172 * cos($city->latitude * 0.0174533))); $minLon = $city->longitude - ($max_distance / (69.172 * cos($city->latitude * 0.0174533))); // Simplify terms to speed query $originLatRadCos = cos($city->latitude * 0.0174533); $originLatRadSin = sin($city->latitude * 0.0174533); $originLonRad = $city->longitude * 0.0174533; $city_distance_query = " SELECT city_id, 3963 * acos(($originLatRadSin * sin( latitude * 0.0174533)) + ($originLatRadCos * cos(latitude * 0.0174533) * cos((longitude * 0.0174533) - $originLonRad))) AS distanceFromOrigin FROM cities WHERE latitude < $maxLat AND latitude > $minLat AND longitude < $maxLon AND longitude > $minLon"; 

Остальная часть запроса

 SELECT cities.city_name, CityDistance.distanceFromOrigin, FROM cities INNER JOIN ($city_distance_query) AS CityDistance ON CityDistance.city_id=cities.city_id WHERE (distanceFromOrigin < $distance OR distanceFromOrigin IS NULL) 

Я думаю, что вам не хватает некоторых скобок и логические операторы немного перепутаны. Как насчет этого.

 $query = "SELECT * FROM places WHERE "; $query .= "((lat BETWEEN $latmin_2 AND $latmax_2) AND NOT (lat BETWEEN $latmin AND $latmax)) AND "; $query .= "((lng BETWEEN $lngmin_2 AND $lngmax_2) AND NOT (lng BETWEEN $lngmin AND $lngmax)) AND "; 

РЕДАКТИРОВАТЬ

Чтобы решить проблему круг / квадрат:

 $query = "SELECT * FROM places WHERE "; $query .= "(POW((lat - $lat) * $avgMilesPerLatDeg,2) + ". "POW((lng - $lng) * $avgMilesPerLngDeg,2) BETWEEN 1 AND 4)"; // the four at the end is 2 squared 

Я бы предложил использовать этот подход, если ваше приложение не является крупномасштабным (с географической точки зрения), а среднее значение дает приемлемые результаты. Вычисление реального расстояния занимает больше времени для вычисления, и разница может быть не такой большой. Это зависит от вас и цели вашего приложения.

Вот что, я думаю, вам нужно: вычислить расстояние в MySQL, используя lat / lng . Это даст вам круг и возможность иметь исключение, в котором вы нуждаетесь.

Выполните шаги, описанные в сообщении, но вместо

 HAVING `distance`<= 10 

Вам нужно будет положить

 HAVING `distance` BETWEEN 1 AND 2 

Это даст вам материал в пределах диапазона.

PS: Если у вас есть база данных с большим количеством записей, вам нужно будет проверить, как она будет работать, и сделать некоторую оптимизацию (если производительность неприемлема)