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.

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top