user970225 user970225 - 2 months ago 20
MySQL Question

Find all Zipcodes within specified distance of a zipcode

I know this question sounds like a repeat of few questions here, but none of those questions answered what i wanted.
I am interested in knowing if someone know how to find other zipcodes within the radius of a specified zipcode. I have the zipcode database with me with latitudes n longitudes but am not sure how to do this in VB.net

e.g - 90069 is a zipcode and if someone says 5 miles radius then i want all the zipcodes like 90210,90045,90034 etc to pop up.

Code samples shall be greatly appreciated

EDIT: I have MySQL server database.

Answer

Here's something I wrote quite a while back that may start you in the correct direction.

While you asked for VB.Net, what you really need is a query that does a "Great Circle Distance" calculation to determine the distance between two points identified by latitude and longitude.

So, making the following assumptions:

  1. Your zip code data is in a single table.
  2. Said table has attributes for lat and lon that are the approximate centroid of the zip code

You could use a LINQ to SQL query that produces the desired result set using something like this

Const EARTH_RADIUS As Single = 3956.0883313286095
Dim radCvtFactor As Single = Math.PI / 180
Dim zipCodeRadius As Integer = <Your Radius Value>

Dim zipQry = From zc In db.ZipCodes 
             Where zc.Zip = "<Your Zip Code>" _
             Select zc.Latitude, 
                    zc.Longitude, 
                    ZipLatRads = RadCvtFactor * zc.Latitude, 
                    ZipLonRads = RadCvtFactor * zc.Longitude
Dim zipRslt = zipQry.SingleOrDefault()
If zipRslt IsNot Nothing Then
    Dim zcQry = From zc In db.ZipCodes _
                Where zc.Latitude >= (zipRslt.Latitude - 0.5) And zc.Latitude <= (zipRslt.Latitude + 0.5) _
                And zc.Longitude >= (zipRslt.Longitude - 0.5) And (zc.Longitude <= zipRslt.Longitude + 0.5) _
                And Math.Abs(EARTH_RADIUS * (2 * Math.Atan2(Math.Sqrt(Math.Pow(Math.Sin(((RadCvtFactor * zc.Latitude) - zipRslt.ZipLatRads) / 2), 2) + _
                Math.Cos(zipRslt.ZipLatRads) * Math.Cos(RadCvtFactor * zc.Latitude) * _
                Math.Pow(Math.Sin(((RadCvtFactor * zc.Longitude) - zipRslt.ZipLonRads) / 2), 2)), _
                Math.Sqrt(1 - Math.Pow(Math.Sin(((RadCvtFactor * zc.Latitude) - zipRslt.ZipLatRads) / 2), 2) + _
                Math.Cos(zipRslt.ZipLatRads) * Math.Cos(RadCvtFactor * zc.Latitude) * _
                Math.Pow(Math.Sin((RadCvtFactor * zc.Longitude) / 2), 2))))) <= zipCodeRadius _
                Select zc
End If

It looks complicated, because it is. There are far smarter people here on SO that can explain the algorithm. I merely implemented this from some SQL code I found on the internet - I can't recall from where. A Google search should get you there.

The first query (zipQry) returns the lat and lon of the starting zip code in both degrees and radians. These results are then used to execute the second query.

The first part of the WHERE clause in the second query:

Where zc.Latitude >= (zipRslt.Latitude - 0.5) And zc.Latitude <= (zipRslt.Latitude + 0.5) _
And zc.Longitude >= (zipRslt.Longitude - 0.5) And (zc.Longitude <= zipRslt.Longitude + 0.5) _

Just narrowed down the list of zip codes to be examined, making the query run much faster. It adds an arbitrary amount to the lat and lon so that you're not checking all the zipcodes in Ohio when searching for a radius in California. The rest is all part of the aforementioned Great Circle Distance algorithm.

This could probably have been done in one query for greater efficiency, but I needed it in this fashion at the time, the reasons now lost to me.

Comments