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.)
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.
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...
While Captaintokyo's method is accurate, it's also fairly slow. I can't help but think it'd be more advantageous to use a temporary table of all zipcodes whose boundaries are within the range, then to refine those results by distance.
来源:https://stackoverflow.com/questions/4011944/mysql-select-zipcodes-within-x-km-miles-within-range-of-y