2010-10-25 3 views
2

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

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

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

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

Теперь я хочу, чтобы найти все другие Почтовые индексы с $range от $baseZipCode.

Например:

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

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

У кого-нибудь есть идеи?


UPDATE Благодаря Captaintokyo я нашел это:

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

Сначала вам потребуется база данных всех Почтовые индексы и их соответствующие координаты широты и долготы:

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`) 
) 

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

ответ

0

Вы хотите сделать что-то вроде этого:

SELECT zipcode FROM zipcodes WHERE DistanceFormula(lat, long, 4.808855, 52.406332) < $range

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

4

Вы должны использовать что-то называется Haversine formula:

$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 ''; 
} 

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

+0

Ваш комментарий к формуле haversine мне очень помог. Однако ваш запрос не совпадает с тем, который я нашел. Я обновил свою тему с правильным запросом. –

+3

Похоже, вы предлагаете мой ответ неверно. Просто хочу отметить, что он отлично работает с моим приложением. Поздравляем с поиском другой функции, которая делает то же самое. – Mischa

+1

Какая единица измерения расстояния находится здесь? –

2

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

Смежные вопросы