mySQL выбирает zipcodes в пределах x км / миль в пределах диапазона y

Примечание. Хотя я использую базу данных zipcode с голландскими zipcodes, этот вопрос не зависит от страны.

У меня есть база данных с каждым zipcode в Нидерландах + координата x и y (lat / long).

У меня есть, например, zipcode: $baseZipCode = 1044; со следующими координатами:

 x coordinate = 4,808855 y coordinate = 52,406332 

Теперь я хочу найти все другие zipcodes с $range от $baseZipCode .

Например:

 SELECT zipcode FROM zipcodes WHERE ????? // Need help here 

Проблема в том, что земля не полностью кругла. Я нахожу много учебников с from a to b вычислений, но это не то, что мне нужно.

Кто-нибудь есть идеи?


ОБНОВЛЕНИЕ Благодаря Captaintokyo я нашел это:

Хотите найти все zipcodes и соответствующие расстояния в радиусе определенной мили / километр от другого почтового индекса или точки? Эти проблемы требуют решения координат широты и долготы. Геокодирование адреса дает координаты широты / долготы с адреса.

Сначала вам понадобится база данных всех 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

    Это может быть медленным, если ваша таблица почтовых индексов велика. Вы также можете проверить геопространственные расширения для MySQL.

    Вы должны использовать что-то, называемое формулой Хаверсина :

     $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, границы которой находятся в пределах диапазона, а затем уточнять эти результаты по расстоянию.