The following stored functions can calculate the distance between two coordinates using a couple different approximation methods. The return value is in miles.
Haversine approximation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
DELIMITER $$
DROP FUNCTION IF EXISTS `mydb`.`distance_HAVERSINE` $$
CREATE FUNCTION `distance_HAVERSINE`(
lat1 FLOAT(9,6),
lon1 FLOAT(9,6),
lat2 FLOAT(9,6),
lon2 FLOAT(9,6)
)
RETURNS INT
DETERMINISTIC
COMMENT 'distance calculated using haversine function'
BEGIN
RETURN 3956 * 2 *
ASIN(
SQRT(
POWER(SIN((lat1 - lat2) * pi()/180 / 2), 2) +
COS(lat1 * pi()/180) *
COS(lat2 * pi()/180) *
POWER(SIN((lon1 - lon2) * pi()/180 / 2), 2)
)
);
END $$
DELIMITER ;
|
Spherical cosines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
DELIMITER $$
DROP FUNCTION IF EXISTS `mydb`.`distance_COSINES` $$
CREATE FUNCTION `distance_COSINES`(
DELIMITER $$
DROP FUNCTION IF EXISTS `mydb`.`distance_COSINES` $$
CREATE FUNCTION `distance_COSINES`(
lat1 FLOAT(9,6),
lon1 FLOAT(9,6),
lat2 FLOAT(9,6),
lon2 FLOAT(9,6))
RETURNS INT
DETERMINISTIC
COMMENT 'distance calculated using spherical law of cosines function'
BEGIN
RETURN 3956 *
ACOS(
SIN(lat1 * 0.0174532925) *
SIN(lat2 * 0.0174532925) +
COS(lat1 * 0.0174532925) *
COS(lat2 * 0.0174532925) *
COS((lon2 - lon1) * 0.0174532925)
);
END $$
DELIMITER ;
|
Furthermore this can be sped up significantly by making a few assumptions.
1 degree of Latitude equals approximately 69 miles
1 degree of Longitude equals approximately ABS(COS(radian(origin point latitude in degrees)))*69 miles.
Here's a sample of how we can use these assumptions. Assuming we have a table of zip codes with logitutde
and latitude, we can retrieve all zip codes within a range from a starting zip code. We can thus figure out
all zip codes within 5 miles of 90210 with a query like:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
SELECT
dest.col_zip_code
FROM
tbl_zip_code dest,
tbl_zip_code orig
WHERE
orig.col_zip_code = '90210' AND
dest.col_latitude BETWEEN
orig.col_latitude - 5/69 AND
orig.col_latitude + 5/69 AND
dest.col_longitude BETWEEN
orig.col_longitude - 5/abs(cos(radians(orig.col_latitude))*69) AND
orig.col_longitude + 5/abs(cos(radians(orig.col_latitude))*69);
|
This approach is several orders faster than the previous two functions with similar accuracy.