tags:

views:

73

answers:

5

I have a SQL database where I store longitude and latitude from an iPhone application. I need to query all the records starting from a given location to the other far most location.

For example, I have longitude x and latitude y. I want all the records first whose longitude matches x the most closely and whose latitude matches y the most closely. I need to all the records one by one in the chain from nearest to farthest. The more distant the location, the greater the value of longitude and latitude will be than x and y.

I hope you got the point and I am waiting for the answer.

A: 

Assuming that you've queried the start location lat/lon and location ID... I am using $LAT, $LON, and $ID as placeholders:

select locID, locName, locDesc, lat, lon, locDiff
from (
    select locID, locName, locDesc, lat, lon, ABS(lat - $LAT) + ABS(lon - $LON) as locDiff
      from locationTable
    where locID <> $ID
) a
order by locDiff

Hopefully this helps... may not be the most optimized method, but it should be pretty close.

Fosco
sorry but can you explain this query?
Umair Ashraf
Which part of it is confusing you?. The inner sub query pulls all of the locations except the one you're comparing against, and subtracts the latitude and longitude values from the one you're comparing against. It uses the ABS function to get the absolute (non-negative) value of the results. The outer query just pulls the data from the inner query ordered by the distance. After seeing it, I would recommend Mark Bannisters answer which uses a more accurate theorem.
Fosco
+1  A: 

Similar to Fosco, but using Pythagoras' Theorem:

select locID, locName, locDesc, lat, lon, locDiff from
(select locID, locName, locDesc, lat, lon, 
 sqrt((lat - $LAT)*(lat - $LAT) + (lon - $LON)*(lon - $LON)) as locDiff
 from locationTable
 where locID <> $ID) a
order by locDiff

For really large distances (or locations far from the equator) you should ideally use a geodesic.

Mark Bannister
+2  A: 

Distance with latitude and longitude is not a simple calculation, but one requiring spherical trigonometry.

acos(cos(lat1)*cos(lon1)*cos(lat2)*cos(lon2) + 
     cos(lat1)*sin(lon1)*cos(lat2)*sin(lon2) + 
     sin(lat1)*sin(lat2)) * R(adius of the earth)

So this query

select locID, locName, locDesc, lat, lon, locDiffMeters   
from (select locID, locName, locDesc, lat, lon, 
             acos(cos($lat)*cos($lon)*cos(lat)*cos(lon) + 
                  cos($lat)*sin($lon)*cos(lat)*sin(lon) + 
                  sin($lat)*sin(lat) ) * 6,371,000 -- earths radius in meters
               as locDiffMeters
      from locationTable    
    where locID <> $ID    
) a    
order by locDiffMeters    

Is probably the right answer, assuming you have that capable of a math library.

Adam Musch
your answer looks cool. I am not that good at maths but trying to figure out your query.Can you tell me why did you take other fields than Lon/Lat in your query?
Umair Ashraf
I used Fosco's base query above/below, just changing the distinct calculation to use actual distance on a sphere. You need a starting point (indicated by $ID, $LAT, and $LON) and we assume your table of points has locID, locName, locDesc, lat, and lon. You didn't provide a table definition; we'd have used one if it had been provided (hint, hint).
Adam Musch
A: 

If you don't have to deal with large distances (see Adam's answer), you might consider using PostgreSQL's geometric types and associated functions.

Justin K
A: 

If you're using Postgresql, add the PostGIS extension and check out the ST_Distance_Sphere

ST_Distance_Sphere — Returns minimum distance in meters between two lon/lat geometries. Uses a spherical earth and radius of 6370986 meters. Faster than ST_Distance_Spheroid, but less accurate. PostGIS versions prior to 1.5 only implemented for points.

SELECT round(CAST(ST_Distance_Sphere(ST_Centroid(the_geom), ST_GeomFromText('POINT(-118 38)',4326)) As numeric),2) As dist_meter ...
Evan Carroll