MySQL Выберите Zipcodes в X Km / Miles в пределах досягаемости Y

StackOverflow https://stackoverflow.com/questions/4011944

Вопрос

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top