Thanks for the snippet. Turns out I found the same database before googling here and found the same resource for distance calcs. Your citation is meridianworlddata.com/Distance-Calculation.asp.
Not a programmer - a pretty fair engineer-mathematician 30 years ago but my comments for what they are worth:
* I think using zip_gcd may be overkill in zip_radius given that it uses a more approximate formula to filter. You know better than I whether it will make a perceptible difference in performance. * I believe that the left side of the filter in zip_radius will always return statute miles while a user may be seduced into entering radius in the units specified by type
I've found alot of applications on the web where people are attempting a radius search, so the work you did is pertinent. I haven't found any that require accuracy greater than +-10%, so my approach will be to use the simplest approximation.
I ran an error check on the distance approximations using Census Bureau data from Autauga County, AL to all other counties in the 48 contiguous states + AK. Average error was 3.5% for the simplest, 2% for the more accurate approximation. Results were as bad as 30% off to points close to the north pole, but fine everywhere else.
I did clean up the database and replaced records where the 2000 Census defined a Zip Code Tabulation Area. Still a work in progress and, of course in Excel, but if I figure out how to make it available I will.
Should leave the programming to programmers, after playing with your snippet, crashing the server, balooning execution time, and finally understanding a little more SQL, I see why the overkill was ok.
I pared down your snippet to just a simple radius search in an 'unworldly' way and included it below. Application is joining with an address table to find out who lives within x miles. Any hint how to do that?
DELIMITER $
DROP PROCEDURE IF EXISTS zip_radius$
CREATE PROCEDURE zip_radius(IN zip_start VARCHAR(5), IN radius INT, prec INT)
BEGIN
DECLARE src_lat DOUBLE;
DECLARE src_long DOUBLE;
SELECT latitude, longitude INTO src_lat, src_long FROM zipcodes WHERE zip = zip_start;
SELECT zip, city, state, county, ROUND(SQRT(POW(69.1 * ( latitude - src_lat ),2)+POW(53.0 * ( longitude - src_long ),2)), prec) AS `distance`
FROM zipcodes
WHERE zip != zip_start
AND POW(69.1 * ( latitude - src_lat ),2)+POW(53.0 * ( longitude - src_long ),2) <= (radius * radius)
ORDER BY `distance` ASC;
END$
DELIMITER ;
As long as you have some way of getting the latitude and longitude for your zip code, you can easily use these procedures and functions. My code is written to exploit a single table that holds nothing but city, state, and latitude/longitude information for a zip code. You can then in turn get your zip code from your address table and get the zips in range using zip_radius().
If you need further help, my username for gmail is dohpaz.
Gives you the ability to implement the Distance and Radius API atZIP Code Download with PHP to get a list of ZIP Codes in a radius. You would need the API and any ZIP Code database with lat/long coordinates to implement it fully.
<?php //THESE FILES ARE AVAILABLE FROM ZIPCODEDOWNLOAD.COM include("DistanceAssistant.inc"); include("RadiusAssistant.inc");
//Simulate data entry $ZIPCode = "90210"; $Miles = "23.74";
//Connect to database $dbhost = "myhost"; //computer name or IP address $dbuser = "myUserName"; $dbpass = "myPassword"; $db = "myDB_Name";
$dbConn = @mysql_connect($dbhost, $dbuser, $dbpass) or die("The site database is down. Please try logging on later."); if($db!="" and !@mysql_select_db($db)) die("The site database is unavailable. Please try logging on later.");
$sql = "SELECT Latitude,Longitude FROM ZIPCodes WHERE ZIPCode = '$ZIPCode'"; if(!$result = mysql_query($sql)){ //Error in mySQL query print"There was an error in sql statement, ".mysql_error()."<br><b>$sql</b>"; exit; } elseif($result==""){ //ZIP code does not exist - report to user... echo"ZIP code does not exist"; } else{ //ZIP code exists $myrow = mysql_fetch_array($result); $Latitude = $myrow["Latitude"]; $Longitude = $myrow["Longitude"];
//mySQL Query $sql = "SELECT * FROM ZIPCodes WHERE
Latitude >= $minLat
AND Latitude <= $maxLat
AND Longitude >= $minLong
AND Longitude <= $maxLong";
if(!$result = mysql_query($sql)){ //Error in mySQL query print"There was an error in sql statement, ".mysql_error()."<br><b>$sql</b>"; exit; } else{ $zcdDistance = new DistanceAssistant; while($myrow = mysql_fetch_array($result)){ $Distance = $zcdDistance->Calculate($Latitude,$Longitude,$myrow["Latitude"],$myrow["Longitude"]); if($Distance <= $Miles){ //this ZIP Code is within $Miles of $ZIPCode //Display appropriate information to the user... printf("%s - %s<br>\n", $myrow["City"], $Distance); } } } } mysql_close($dbConn); ?>
Not a programmer - a pretty fair engineer-mathematician 30 years ago but my comments for what they are worth:
* I think using zip_gcd may be overkill in zip_radius given that it uses a more approximate formula to filter. You know better than I whether it will make a perceptible difference in performance.
* I believe that the left side of the filter in zip_radius will always return statute miles while a user may be seduced into entering radius in the units specified by type
I've found alot of applications on the web where people are attempting a radius search, so the work you did is pertinent. I haven't found any that require accuracy greater than +-10%, so my approach will be to use the simplest approximation.
I ran an error check on the distance approximations using Census Bureau data from Autauga County, AL to all other counties in the 48 contiguous states + AK. Average error was 3.5% for the simplest, 2% for the more accurate approximation. Results were as bad as 30% off to points close to the north pole, but fine everywhere else.
I did clean up the database and replaced records where the 2000 Census defined a Zip Code Tabulation Area. Still a work in progress and, of course in Excel, but if I figure out how to make it available I will.
Thanks again.
I pared down your snippet to just a simple radius search in an 'unworldly' way and included it below. Application is joining with an address table to find out who lives within x miles. Any hint how to do that?
If you need further help, my username for gmail is dohpaz.
<?php
//THESE FILES ARE AVAILABLE FROM ZIPCODEDOWNLOAD.COM
include("DistanceAssistant.inc");
include("RadiusAssistant.inc");
//Simulate data entry
$ZIPCode = "90210";
$Miles = "23.74";
//Connect to database
$dbhost = "myhost"; //computer name or IP address
$dbuser = "myUserName";
$dbpass = "myPassword";
$db = "myDB_Name";
$dbConn = @mysql_connect($dbhost, $dbuser, $dbpass) or die("The site database is down. Please try logging on later.");
if ($db!="" and !@mysql_select_db($db))
die("The site database is unavailable. Please try logging on later.");
$sql = "SELECT Latitude,Longitude FROM ZIPCodes WHERE ZIPCode = '$ZIPCode'";
if (!$result = mysql_query($sql)) {
//Error in mySQL query
print "There was an error in sql statement, ".mysql_error()."<br><b>$sql</b>";
exit;
}
elseif ($result=="") {
//ZIP code does not exist - report to user...
echo "ZIP code does not exist";
}
else {
//ZIP code exists
$myrow = mysql_fetch_array($result);
$Latitude = $myrow["Latitude"];
$Longitude = $myrow["Longitude"];
$zcdRadius = new RadiusAssistant($Latitude,$Longitude,$Miles);
$minLat = $zcdRadius->MinLatitude();
$maxLat = $zcdRadius->MaxLatitude();
$minLong = $zcdRadius->MinLongitude();
$maxLong = $zcdRadius->MaxLongitude();
//mySQL Query
$sql = "SELECT * FROM ZIPCodes WHERE
Latitude >= $minLat
AND Latitude <= $maxLat
AND Longitude >= $minLong
AND Longitude <= $maxLong";
if (!$result = mysql_query($sql)) {
//Error in mySQL query
print "There was an error in sql statement, ".mysql_error()."<br><b>$sql</b>";
exit;
}
else {
$zcdDistance = new DistanceAssistant;
while ($myrow = mysql_fetch_array($result)){
$Distance = $zcdDistance->Calculate($Latitude,$Longitude,$myrow["Latitude"],$myrow["Longitude"]);
if ($Distance <= $Miles){
//this ZIP Code is within $Miles of $ZIPCode
//Display appropriate information to the user...
printf ("%s - %s<br>\n", $myrow["City"], $Distance);
}
}
}
}
mysql_close($dbConn);
?>