Запросы, чтобы найти места в пределах данного широты - PullRequest
6 голосов
/ 27 февраля 2011

Так что я пытаюсь отобразить списки мест в диапазоне заданного широты / долготы. У меня нет проблем с этим:

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

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

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";

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

Ответы [ 3 ]

4 голосов
/ 27 февраля 2011

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

$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) 
2 голосов
/ 27 февраля 2011

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

$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

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

0 голосов
/ 27 февраля 2011

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

Следуйте инструкциям, описанным в посте, но вместо

HAVING `distance`<= 10

вам нужно будет поставить

HAVING `distance` BETWEEN 1 AND 2

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...