views:

59

answers:

3

Note: Although I use a zipcode database with Dutch zipcodes, this question is country independent.

I have a database with every zipcode in the Netherlands + its x and y coordinate (lat/long).

I have for example zipcode: $baseZipCode = 1044; with the following coordinates:

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

Now, I want to find all other zipcodes with $range from $baseZipCode.

For example:

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

The problem is that the earth is not completely round. I find a lot of tutorials with from a to b calculations but that's not what I need.

Does anyone have any idea?


UPDATE Thanks to Captaintokyo I found this:

Want to find all zipcodes and corresponding distances within a certain mile/kilometer radius from another zipcode or point? This problems require latitude and longitude coordinates to solve. Geocoding the address gives you latitude/longitude coordinates from an address.

First you will need a database of all zipcodes and their corresponding latitude and longitude coordinates:

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

So once you have the database you want to find all zipcodes within a certain mile radius of a central point. If the central point is another zipcode, simply query the database for the latitude and longitude coordinates of that zipcode. Then the code is as follows:

// 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";

}

(Both Yahoo and Google offer free geocoding services.)

A: 

You want to do something like this:

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

It may be slow if your table of zip codes is large. You may also want to check out the geospatial extensions for MySQL.

Joshua Martell
A: 

You have to use something called the Haversine formula:

$sql = "
    SELECT zipcode
    FROM zipcodes
    WHERE ".mysqlHaversine($lat, $lon, $distance)."
";

And the formula:

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

Usually I do not use code without understanding the way it works first, but I must confess this function is a little bit over my head...

captaintokyo
Your comment about the haversine formula helped me a lot. However, your query is not the same as the one I've found. I updated my topic with the correct query..
Enrico Pallazzo
It sounds like you are suggesting my answer is incorrect. Just want to point out that it works perfectly my application. Congratulations on finding a different function that does the same thing.
captaintokyo
A: 

If possible approach the problem as per my answer here: http://stackoverflow.com/questions/3983325/calculate-distance-between-zip-codes-and-users/3989830#3989830

hope it helps...

f00