Implementing Zip Code Proximity Functions in MS SQL Server

This post is in the continuing series of articles on database functions, stored procedures, and implementing ZIP code proximity functionality.

Recently I had the opportunity to work on a project involving SQL Server. Having focused mostly on open source databases, I decided to brush up on SQL Server by going through the exercise of implementing the ZIP code proximity functions in T-SQL. The following User-Defined Functions (UDF) were developed and tested in SQL Server 2008 R2 Express, but should be compatible with older versions of SQL Server as well.

First we start with a simple table containing a list of ZIP codes, their latitude and longitude coordinates, city name, state name, and state abbreviation.

CREATE TABLE zipcodes (
   zipcode nvarchar(5) NOT NULL,
   lat float NULL,
   lon float NULL,
   city nvarchar(30) NOT NULL,
   state nvarchar(30) NOT NULL,
   state_abbrev nvarchar(2) NOT NULL
)

CalculateDistance is the function that, as it’s name suggests, calculates the distance between two points. While this function can be called directly, it’s intended to be called from the ZipProximity funtion.

CREATE FUNCTION CalculateDistance(@lat1 float, @lon1 float, @lat2 float, @lon2 float)
RETURNS float
WITH EXECUTE AS CALLER
AS
BEGIN
   DECLARE @Distance float
   SET @Distance = 3959 * ACOS(SIN(RADIANS(@lat1)) * SIN(RADIANS(@lat2)) + COS(RADIANS(@lat1)) * COS(RADIANS(@lat2)) * COS((RADIANS(@lon2) - RADIANS(@lon1))));
   RETURN(@Distance);
END;

ZipProximity leverages CalculateDistance to determine which ZIP codes are within the provided radius. We iterate through all rows and return a table of ZIP codes that are within our radius. The table resembles the original zipcodes table, except that it includes a distance column that will be populated with the distance from our “home” ZIP code.

CREATE FUNCTION ZipProximity(@zip nvarchar(5), @radius integer)
RETURNS @retZipcodes TABLE
(
	zipcode nvarchar(5),
	lat float,
	lon float,
	city_name nvarchar(30),
	state_name nvarchar(30),
	state_abbrev nvarchar(2),
	distance float
)
AS
BEGIN
   DECLARE @home_lat float
   DECLARE @home_lon float

   SELECT @home_lat=lat, @home_lon=lon  FROM zipcodes WHERE zipcode = @zip;

   INSERT @retZipcodes
   SELECT zipcode, lat, lon, city, state, state_abbrev, dbo.CalculateDistance(@home_lat, @home_lon, lat, lon) AS distance
   FROM zipcodes WHERE dbo.CalculateDistance(@home_lat, @home_lon, lat, lon) < @radius ORDER BY distance;
   RETURN

END;

Using what we've just created, here's what a query might look like. We are querying all ZIP codes in a five mile radius of Cupertino, CA 95014.

SELECT * FROM dbo.ZipProximity('95014', 5);

zipcode lat          lon            city          state          state_abbrev distance
------- ------------ -------------- ------------- -------------- ------------ ----------------------
95014   37.30008     -122.09811     CUPERTINO     CALIFORNIA     CA           0
95015   37.32287     -122.05379     CUPERTINO     CALIFORNIA     CA           2.90040921217205
94024   37.34355     -122.10859     LOS ALTOS     CALIFORNIA     CA           3.05837716732744
95070   37.25798     -122.03213     SARATOGA      CALIFORNIA     CA           4.64994222426924
94087   37.34562     -122.03196     SUNNYVALE     CALIFORNIA     CA           4.80768907001485

But the advantage of returning a table is that you can query it with more advanced SQL.
Here we are only interested in the ZIP code, city, and state abbreviation for ZIP codes within a five mile radius of Cupertino, CA. but greater than a three mile radius.

SELECT zipcode, city, state_abbrev, distance FROM dbo.ZipProximity('95014', 5) WHERE distance > 3;

zipcode  city         state_abbrev  distance
-------  -----------  ------------  -----------------
94024	 LOS ALTOS    CA            3.05837716732744
95070	 SARATOGA     CA            4.64994222426924
94087	 SUNNYVALE    CA            4.80768907001485
This entry was posted in SQL Server. Bookmark the permalink.

One Response to Implementing Zip Code Proximity Functions in MS SQL Server

  1. Pingback: CLR User-Defined Functions in C# | iamtgc

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>