First, the MySQL stuff: DELIMITER $ DROP FUNCTION IF EXISTS zip_deg2rad$ DROP FUNCTION IF EXISTS zip_gcd$ DROP FUNCTION IF EXISTS zip_distance$ DROP PROCEDURE IF EXISTS zip_radius$ CREATE FUNCTION zip_deg2rad(degrees DOUBLE) RETURNS DOUBLE BEGIN RETURN degrees / (180 / PI()+0.000000000000000); END$ CREATE FUNCTION zip_gcd(type ENUM('M', 'N', 'K'), src_lat DOUBLE, src_long DOUBLE, dst_lat DOUBLE, dst_long DOUBLE) RETURNS DOUBLE BEGIN DECLARE temp DOUBLE; DECLARE STATUTE_MILES DECIMAL(5,1); DECLARE NAUTICAL_MILES DECIMAL(9,5); DECLARE KILOMETERS DECIMAL(5,1); SET STATUTE_MILES = 3963.0; SET NAUTICAL_MILES = 3437.74677; SET KILOMETERS = 6378.7; SET src_lat = zip_deg2rad(src_lat); SET src_long = zip_deg2rad(src_long); SET dst_lat = zip_deg2rad(dst_lat); SET dst_long = zip_deg2rad(dst_long); SET temp = ACOS(SIN(src_lat) * SIN(dst_lat) + COS(src_lat) * cos(dst_lat) * cos(dst_long - src_long)); IF type = "M" THEN SET temp = STATUTE_MILES * temp; END IF; IF type = "N" THEN SET temp = NAUTICAL_MILES * temp; END IF; IF type = "K" THEN SET temp = KILOMETERS * temp; END IF; RETURN temp; END$ CREATE FUNCTION zip_distance(type ENUM('M', 'N', 'K'), zip_start VARCHAR(5), zip_finish VARCHAR(5)) RETURNS DOUBLE BEGIN DECLARE distance DOUBLE; DECLARE start_lat DOUBLE; DECLARE start_long DOUBLE; DECLARE finish_lat DOUBLE; DECLARE finish_long DOUBLE; SELECT latitude, longitude INTO start_lat, start_long FROM zipcodes WHERE zip = zip_start; SELECT latitude, longitude INTO finish_lat, finish_long FROM zipcodes WHERE zip = zip_finish; SELECT zip_gcd(type, start_lat, start_long, finish_lat, finish_long) INTO distance; RETURN distance; END$ CREATE PROCEDURE zip_radius(IN type ENUM('M', 'N', 'K'), 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(zip_gcd(type, src_lat, src_long, latitude, longitude), prec) AS `distance` FROM zipcodes WHERE zip != zip_start AND (POW((69.1 * (longitude - src_long) * COS(src_lat / 57.3)), 2) + POW((69.1 * (latitude - src_lat)), 2)) <= (radius * radius) ORDER BY `distance` ASC; END$ DELIMITER ; To use these, here are a few examples:
  • As a note: for zip_gcd, zip_distance, and zip_radius; type is one of M (Miles), N (Nautical Miles), or K (Kilometers)
  • SELECT zip_gcd('M', 40.922326, -72.637078, 33.786594, -118.298662) AS `distance`;
    Will return: 2529.2219424646 miles from Holtsville, NY to Palmdale, Ca
  • SELECT zip_distance('K', '28105', '00653');
    Will return: 2346.5488627315 kilometers from Matthews, NC to Guanica, Peurto Rico
  • CALL zip_radius('N', '28105', 10, 0);
    Will return 14 zip codes within a 10-nautical-mile radius from Matthews, NC (not including 28105), rounded to the nearest nautical mile
  • Here is an example PHP script that will return all of the zip codes within a 10-mile radius from Charlotte, NC: real_query($sql)) { printf("Invalid query: %s\nWhole query: %s\n", $mysqli->error, $sql); exit; } if ($result = $mysqli->store_result()) { while ($record = $result->fetch_assoc()) { $records[] = $record; } $result->close(); } $mysqli->close(); print_r($records); ?> Just change the dbuser and dbpass to their respective credentials, and run this script to see the following output: Array ( [0] => Array ( [zip] => 28217 [city] => CHARLOTTE [state] => NC [county] => MECKLENBURG [distance] => 2 ) [1] => Array ( [zip] => 28134 [city] => PINEVILLE [state] => NC [county] => MECKLENBURG [distance] => 4 ) [2] => Array ( [zip] => 29716 [city] => FORT MILL [state] => SC [county] => YORK [distance] => 5 ) [3] => Array ( [zip] => 28210 [city] => CHARLOTTE [state] => NC [county] => MECKLENBURG [distance] => 5 ) ) It is very important to note that every single time you use zip_radius and zip_distance to remember to ALWAYS quote the zip codes. Since some of these zip codes start with a zero, not quoting them will produce NULL results from MySQL. This is because MySQL will treat them as numbers, and as such, numbers do not start with zeros. [smile]