MySQL Выберите Zipcodes в X Km / Miles в пределах досягаемости Y
-
26-09-2019 - |
Вопрос
Примечание. Несмотря на то, что я использую базу данных Zipcode с голландскими почтовыми почтами, этот вопрос является независимой страной.
У меня есть база данных с каждым zipcode в Нидерландах + его координата x и y (lat / long).
У меня например Zipcode: $baseZipCode = 1044;
со следующими координатами:
x coordinate = 4,808855
y coordinate = 52,406332
Теперь я хочу найти все остальные почтовые почки с $range
от $baseZipCode
.
Например:
SELECT
zipcode
FROM
zipcodes
WHERE
????? // Need help here
Проблема в том, что земля не полностью раунд. Я нахожу много учебных пособий с from a to b
Расчеты, но это не то, что мне нужно.
У кого-нибудь есть идеи?
ОБНОВИТЬСпасибо Captaintokyo я нашел это:
Хотите найти все Zipcodes и соответствующие расстояния в пределах определенной мили / километра радиуса от другого zipcode или точки? Эти проблемы требуют решения широты и долготы, чтобы решить. Геокодирование адреса дает вам координаты широты / долготы с адреса.
Сначала вам понадобится база данных всех zipcodes и их соответствующие координаты широты и долготы:
CREATE TABLE `zipcodes` (
`zipcode` varchar(5) NOT NULL DEFAULT '',
`city` varchar(100) NOT NULL DEFAULT '',
`state` char(2) NOT NULL DEFAULT '',
`latitude` varchar(20) NOT NULL DEFAULT '',
`longitude` varchar(20) NOT NULL DEFAULT '',
KEY `zipcode` (`zipcode`),
KEY `state` (`state`)
)
Поэтому, как только у вас есть база данных, вы хотите найти все Zipcodes в пределах определенного радиуса мили центральной точки. Если центральная точка является еще одним zipcode, просто запрашивайте базу данных для координатов широты и долготы этого почтового Zipcode. Тогда код выглядит следующим образом:
// ITITIAL POINT
$coords = array('latitude' => "32.8", 'longitude' => "-117.17");
//RADIUS
$radius = 30;
// SQL FOR KILOMETERS
$sql = "SELECT zipcode, ( 6371 * acos( cos( radians( {$coords['latitude']} ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians( {$coords['longitude']} ) ) + sin( radians( {$coords['latitude']} ) ) * sin( radians( latitude ) ) ) ) AS distance FROM zipcodes HAVING distance <= {$radius} ORDER BY distance";
// SQL FOR MILES
$sql = "SELECT zipcode, ( 3959 * acos( cos( radians( {$coords['latitude']} ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians( {$coords['longitude']} ) ) + sin( radians( {$coords['latitude']} ) ) * sin( radians( latitude ) ) ) ) AS distance FROM zipcodes HAVING distance <= {$radius} ORDER BY distance";
// OUTPUT THE ZIPCODES AND DISTANCES
$query = mysql_query($sql);
while($row = mysql_fetch_assoc($query)){
echo "{$row['zipcode']} ({$row['distance']})<br>\n";
}
(Как Yahoo, и Google предлагают бесплатные услуги геокодирования.)
Решение
Вы хотите сделать что-то вроде этого:
SELECT zipcode FROM zipcodes WHERE DistanceFormula(lat, long, 4.808855, 52.406332) < $range
Это может быть медленным, если ваша таблица Zip-кодов велика. Вы также можете проверить геопространственные расширения для MySQL.
Другие советы
Вы должны использовать что-то под названием Формула Haversine:
$sql = "
SELECT zipcode
FROM zipcodes
WHERE ".mysqlHaversine($lat, $lon, $distance)."
";
И формула:
function mysqlHaversine($lat = 0, $lon = 0, $distance = 0)
{
if($distance > 0)
{
return ('
((6372.797 * (2 *
ATAN2(
SQRT(
SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) *
SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) +
COS(latitude * (PI()/180)) *
COS('.($lat*1).' * (PI()/180)) *
SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2) *
SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2)
),
SQRT(1-(
SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) *
SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) +
COS(latitude * (PI()/180)) *
COS('.($lat*1).' * (PI()/180)) *
SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2) *
SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2)
))
)
)) <= '.($distance/1000). ')');
}
return '';
}
Обычно я не использую код, не понимая, как он работает в первую очередь, но я должен признаться, что эта функция немного над головой ...
В то время как метод Captaintokyo является точным, это также довольно медленно. Я не могу не думать, что будет более выгодно использовать временную таблицу всех zipcodes, границы которых находятся в пределах диапазона, затем уточнить эти результаты на расстоянии.