Problems finding distance to other users Sql Server 2005 - Haversine
-
27-10-2019 - |
Question
I have a table with users and I need to find the nearest users based on lat, long. I also need the distance. I have been struggling with the haversine formula and alternatives for two days, but I am facing some errors.
Let's say as an example that I use lat, long for Kuala Lumpur, Malaysia (roughly 3.2, 102).
Using pythagoras:
SELECT top 10 *,
SQRT(SQUARE(ABS(latitude - 3.2)) + SQUARE(ABS(longitude - 102))) AS distance
FROM lfuser
ORDER BY distance
It gives me "correct" results (users near that point). But I can't get the distance (in KM) from that and I know it is not entirely correct. So I have tried to use haversine:
SELECT TOP 10 *,
ROUND(2 * ASIN(SQRT(POWER(SIN(((3.2 / 180) * PI()
- (latitude / 180) * PI()) / 2) ,2) + COS((3.2 / 180) * PI())
* COS((latitude / 180) * PI()) * POWER(SIN(((102 / 180) * PI()
- (longitude / 180) * PI()) / 2), 2))) * 6367, 4) AS distance
FROM lfuser
ORDER BY distance
The strange thing is that this gives me users elsewhere. Actually the top 1 result is a user in Ghana with lat=5.55 and long=-0.20.
This is driving me crazy... I could of course calculate an approximate distance by multiplying the pythagoras result with 110 kms but I would like the more correct result.
I hope someone can point out what is wrong.
Please don't post links to different implementations of haversine formula etc. I have been looking at them for two days now.
Solution
In the past i'd used Haversine in SQL 2005
so i tried to convert my procedure to adapt for your case. Let me know if work fine
I supposed also the correct Kuala Lumpur Longitude and Latitude are 3.139003, 101.686855
declare @myLatitude decimal(12,6), @myLongitude decimal(12,6), @EarthRadius decimal(12,6)
select @myLatitude = 3.139003, @myLongitude = 101.686855, @EarthRadius = 6378.137
SELECT top 10 *,
(@EarthRadius * ACOS((SIN(PI() * @myLatitude /180)
* SIN(PI() * Latitude/180))
+ (COS(PI() * @myLatitude /180)
* COS(PI() * Latitude/180)
* COS(PI() * Longitude/180 - PI() * @myLongitude /180))))
as distance
FROM lfuser
ORDER BY distance
Hope it helps
OTHER TIPS
Just a quick answer for now. If you are using SQL server 2008 you should use the geo types (point in your case) to store the location. There are built-in methods for handling distance between points. Start here and here
You might want to ask this question on: gis.stackexchange.com which specialises in this area.