2

注: 私はオランダの郵便番号を含む郵便番号データベースを使用していますが、この質問は国に依存しません。

オランダのすべての郵便番号とその x 座標と y 座標 (緯度/経度) を含むデータベースがあります。

たとえば$baseZipCode = 1044;、次の座標を持つzipcode: があります。

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

$rangeここで、 fromを使用して他のすべての郵便番号を検索したいと思います$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`)
)

したがって、データベースを取得したら、中心点から一定の半径内にあるすべての郵便番号を検索する必要があります。中心点が別の郵便番号の場合は、その郵便番号の緯度と経度の座標をデータベースに照会するだけです。次に、コードは次のとおりです。

// 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 の両方が無料のジオコーディング サービスを提供しています。)

4

3 に答える 3

4

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

通常、私は最初にその仕組みを理解せずにコードを使用することはありませんが、この関数は私の頭を少し超えていることを告白しなければなりません...

于 2010-10-25T06:27:04.170 に答える
2

Captaintokyo の方法は正確ですが、かなり遅いです。境界が範囲内にあるすべての郵便番号の一時テーブルを使用し、それらの結果を距離で絞り込む方が有利だと思わずにはいられません。

于 2013-03-04T23:34:17.647 に答える
0

あなたはこのようなことをしたいです:

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

郵便番号のテーブルが大きい場合は遅くなる可能性があります。MySQLの地理空間拡張機能も確認することをお勧めします。

于 2010-10-25T05:07:11.577 に答える