216

I have latitude and longitude and I want to pull the record from the database, which has nearest latitude and longitude by the distance, if that distance gets longer than specified one, then don't retrieve it.

Table structure:

id
latitude
longitude
place name
city
country
state
zip
sealevel
miken32
  • 42,008
  • 16
  • 111
  • 154
Basit
  • 16,316
  • 31
  • 93
  • 154
  • 1
    This is sort of a duplicate of the [proximity search](http://stackoverflow.com/questions/260335/proximity-search/260347#260347) question. – Darius Bacon Feb 10 '10 at 03:46
  • 1
    There is a set of slides by Alexander Rubin on [Geo (proximity) search with MySQL](http://www.arubin.org/files/geo_search.pdf) (PDF link) – Martijn Pieters Feb 25 '20 at 07:58
  • Beware of the answers here. Most cannot use any index, hence perform poorly for large datasets. Some are limited to non-spherical distance computation, thereby being not useful in may global applications. – Rick James Jun 05 '21 at 18:18
  • Further discussion, including discussion of scaling, precision, and 5 competing techniques: http://mysql.rjweb.org/doc.php/find_nearest_in_mysql – Rick James Jun 05 '21 at 18:19
  • If the query says `HAVING distance < ...`, then the query is likely to be checking every row and computing the distance for each one. (Slow and not scalable.) – Rick James Jun 05 '21 at 18:27

18 Answers18

267
SELECT latitude, longitude, SQRT(
    POW(69.1 * (latitude - [startlat]), 2) +
    POW(69.1 * ([startlng] - longitude) * COS(latitude / 57.3), 2)) AS distance
FROM TableName HAVING distance < 25 ORDER BY distance;

where [starlat] and [startlng] is the position where to start measuring the distance.

LPL
  • 16,827
  • 6
  • 51
  • 95
Kaletha
  • 3,189
  • 3
  • 19
  • 10
  • 58
    Just a performance note, it's best to not sqrt the distance variable but instead square the '25' test value... later sqrt the results that have passed if you need to show the distance – sradforth Jan 30 '12 at 13:46
  • 11
    What would be the same query for the distance to be in meters ? (which is currently in miles, right?) – httpete Nov 28 '12 at 20:42
  • 1
    Lattitude is measured in degrees. not miles or meters. http://en.wikipedia.org/wiki/Latitude – Menace Jul 07 '13 at 12:49
  • 10
    What measurement is that 25? – Steffan Donal Aug 08 '13 at 21:30
  • 21
    Just to clarify here 69.1 is the conversion factor for miles to latitude degrees. 57.3 is roughly 180/pi, so that's conversion from degrees to radians, for the cosine function. 25 is the search radius in miles. This is the formula to use when using decimal degrees and statute miles. – John Vance Nov 07 '13 at 22:00
  • 8
    Additionally, it does not take into account the curvature of the earth. This would not be an issue for short search radii. Otherwise Evan's and Igor's answers are more complete. – John Vance Nov 08 '13 at 03:46
  • 1
    @JohnVance So the result distance is in miles, right? How to convert that for kilometers, for example? Also Igor's answer takes in account the radius of the earth but it's tooo slow. I got two seconds for Kalethas's answer but for Igor's answer I got like 15! Then what you mean when you say "short" distances? – Patrick Bassut Dec 18 '14 at 20:41
  • 8
    @PatrickBassut , I know this is way late, but for others out there, if you need your "AS distance" to be in kilometers, you just need Km/degree of earth. Since Kaletha has already given you 69.1 miles/deg, then the change would be ~111.2km. [description](http://geography.about.com/library/faq/blqzdistancedegree.htm). Also, just FYI, do not fiddle with the 57.3 value, as stated above, it is a conversion factor for degree to radian. – 1mike12 Feb 26 '15 at 23:44
  • @PatrickBassut, regarding your second question, what the others mean by "short" distances is the drawback of Kaletha's method. The math behind the function assumes that two points lie on a flat, rectangular grid. Obviously, the earth is round, so if you need the distance value to be accurate when comparing distances, say, between two coasts of the US, then this would not be accurate. [distance in cartesian coordinates](http://en.wikipedia.org/wiki/Cartesian_coordinate_system#Distance_between_two_points). Although Igor's is really slow due to all the calculations, it will give you "exact" miles – 1mike12 Feb 26 '15 at 23:50
  • 2
    On Postgres it works only if i remove HAVING clause. `Error: the column distance does not exist`. Why? – smartmouse May 07 '15 at 15:45
  • You cant use distance in HAVING , because distance is not a real column of table,. – Mohammad Shahbaz Jul 07 '22 at 17:27
  • What I should do to set the max distance to 100km ? Is 25 the miles ? – Olavo Mello Jan 18 '23 at 18:50
104

Google's solution:

Creating the Table

When you create the MySQL table, you want to pay particular attention to the lat and lng attributes. With the current zoom capabilities of Google Maps, you should only need 6 digits of precision after the decimal. To keep the storage space required for your table at a minimum, you can specify that the lat and lng attributes are floats of size (10,6). That will let the fields store 6 digits after the decimal, plus up to 4 digits before the decimal, e.g. -123.456789 degrees. Your table should also have an id attribute to serve as the primary key.

CREATE TABLE `markers` (
  `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  `name` VARCHAR( 60 ) NOT NULL ,
  `address` VARCHAR( 80 ) NOT NULL ,
  `lat` FLOAT( 10, 6 ) NOT NULL ,
  `lng` FLOAT( 10, 6 ) NOT NULL
) ENGINE = MYISAM ;

Populating the Table

After creating the table, it's time to populate it with data. The sample data provided below is for about 180 pizzarias scattered across the United States. In phpMyAdmin, you can use the IMPORT tab to import various file formats, including CSV (comma-separated values). Microsoft Excel and Google Spreadsheets both export to CSV format, so you can easily transfer data from spreadsheets to MySQL tables through exporting/importing CSV files.

INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Frankie Johnnie & Luigo Too','939 W El Camino Real, Mountain View, CA','37.386339','-122.085823');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Amici\'s East Coast Pizzeria','790 Castro St, Mountain View, CA','37.38714','-122.083235');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Kapp\'s Pizza Bar & Grill','191 Castro St, Mountain View, CA','37.393885','-122.078916');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Round Table Pizza: Mountain View','570 N Shoreline Blvd, Mountain View, CA','37.402653','-122.079354');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Tony & Alba\'s Pizza & Pasta','619 Escuela Ave, Mountain View, CA','37.394011','-122.095528');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Oregano\'s Wood-Fired Pizza','4546 El Camino Real, Los Altos, CA','37.401724','-122.114646');

Finding Locations with MySQL

To find locations in your markers table that are within a certain radius distance of a given latitude/longitude, you can use a SELECT statement based on the Haversine formula. The Haversine formula is used generally for computing great-circle distances between two pairs of coordinates on a sphere. An in-depth mathemetical explanation is given by Wikipedia and a good discussion of the formula as it relates to programming is on Movable Type's site.

Here's the SQL statement that will find the closest 20 locations that are within a radius of 25 miles to the 37, -122 coordinate. It calculates the distance based on the latitude/longitude of that row and the target latitude/longitude, and then asks for only rows where the distance value is less than 25, orders the whole query by distance, and limits it to 20 results. To search by kilometers instead of miles, replace 3959 with 6371.

SELECT 
id, 
(
   3959 *
   acos(cos(radians(37)) * 
   cos(radians(lat)) * 
   cos(radians(lng) - 
   radians(-122)) + 
   sin(radians(37)) * 
   sin(radians(lat )))
) AS distance 
FROM markers 
HAVING distance < 28 
ORDER BY distance LIMIT 0, 20;

This one is to find latitudes and longitudes in a distance less than 28 miles.

Another one is to find them in a distance between 28 and 29 miles:

SELECT 
id, 
(
   3959 *
   acos(cos(radians(37)) * 
   cos(radians(lat)) * 
   cos(radians(lng) - 
   radians(-122)) + 
   sin(radians(37)) * 
   sin(radians(lat )))
) AS distance 
FROM markers 
HAVING distance < 29 and distance > 28 
ORDER BY distance LIMIT 0, 20;

https://developers.google.com/maps/articles/phpsqlsearch_v3#creating-the-map

Community
  • 1
  • 1
Sviatoslav Oleksiv
  • 2,538
  • 2
  • 13
  • 12
  • 1
    Should it be `HAVING distance < 25` as we querying locations within a radius of 25 miles ? – Vitalii Elenhaupt Feb 01 '17 at 16:17
  • it should be > 25 , then it will search all records – vidur punj Mar 15 '18 at 12:07
  • are you Sure @vidurpunj about > 25 ? – Amranur Rahman Jan 04 '19 at 10:39
  • I tried the sql query using: distance < 25 but found no results .. as the sample markers distances all are above 25 ... – Ibrahim Mohamed Jul 16 '19 at 23:52
  • 37, -122 coordinate, is this latitude and longitude for position from where we need to find the distance? – Prasobh.Kollattu Aug 09 '19 at 08:30
  • This sometimes yields a null distance instead of 0.0 when the record's latitude and longitude are identical to those included in the formula. For example, latitude +35.682395 and longitude +139.792022 yields null distance. I used coalesce(distance,0) to treat the null as zero. I haven't researched further, but my pre-existing latitude/longitude columns are decimal (not float). – David Denenberg Jun 05 '20 at 00:51
  • On Postgres, it works only if I remove the HAVING clause. `Error: the column distance does not exist.` Why? Any alternate suggestions? – Datt Aug 08 '20 at 10:47
  • Why will we need `id` as primary key? We can't we use lat and lng as our primary key? – Devashish Prasad Mar 23 '21 at 15:00
  • "floats of size (10,6) ... will let the fields store 6 digits after the decimal, plus up to 4 digits before the decimal," -- Not true. Instead, `FLOAT` is limited to about 7 _significant_ digits. That is sufficient for most uses. Toss the `(10,6)`; it is deprecated in 8.0.17 and will be removed later. – Rick James Jun 05 '21 at 18:15
  • so far this is the quickest query. it is 7~8% faster than https://stackoverflow.com/a/5548877/4826981 – Mahmoud Kassem Dec 18 '21 at 15:49
40

The original answers to the question are good, but newer versions of mysql (MySQL 5.7.6 on) support geo queries, so you can now use built in functionality rather than doing complex queries.

You can now do something like:

select *, ST_Distance_Sphere( point ('input_longitude', 'input_latitude'), 
                              point(longitude, latitude)) * .000621371192 
          as `distance_in_miles` 
  from `TableName`
having `distance_in_miles` <= 'input_max_distance'
 order by `distance_in_miles` asc

The results are returned in meters. So if you want in KM simply use .001 instead of .000621371192 (which is for miles).

MySql docs are here

Shivam Agarwal
  • 133
  • 1
  • 6
Sherman
  • 827
  • 8
  • 16
  • If possible please add mysql version in answer. – Parixit Oct 08 '18 at 07:12
  • `ST_Distance_Sphere` doesn't exist in my host's install (`mysql Ver 15.1 Distrib 10.2.23-MariaDB`). I read somewhere to substitute `ST_Distance` but the distances are way off. – ashleedawg Jul 21 '19 at 08:04
  • @ashleedawg - From the version, I think you're using MariaDB, which is a fork of mysql. From [this conversation](https://dba.stackexchange.com/questions/183930/mysql-changing-output-unit-of-st-distance-function) it looks like MariaDB hasn't implemented `ST_Distance_Sphere` – Sherman Jul 22 '19 at 20:46
  • This answer should be higher up, as it's the only one that uses the "new" functionality and results in a much nicer query. Although to be honest I'm puzzled by the amount of answers that default to miles instead of the metric system; at least this one bothers to show how to switch between the two. – theberzi Apr 27 '21 at 07:03
  • works great! I coded stuff like this several times and it was always ... But this one was in, out, works! Thank you! I have an issue left, i have three tables with locations. Any idea how to run this select over all of them? – Sascha Grindau Jul 05 '22 at 11:59
33

Here is my full solution implemented in PHP.

This solution uses the Haversine formula as presented in http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL.

It should be noted that the Haversine formula experiences weaknesses around the poles. This answer shows how to implement the vincenty Great Circle Distance formula to get around this, however I chose to just use Haversine because it's good enough for my purposes.

I'm storing latitude as DECIMAL(10,8) and longitude as DECIMAL(11,8). Hopefully this helps!

showClosest.php

<?PHP
/**
 * Use the Haversine Formula to display the 100 closest matches to $origLat, $origLon
 * Only search the MySQL table $tableName for matches within a 10 mile ($dist) radius.
 */
include("./assets/db/db.php"); // Include database connection function
$db = new database(); // Initiate a new MySQL connection
$tableName = "db.table";
$origLat = 42.1365;
$origLon = -71.7559;
$dist = 10; // This is the maximum distance (in miles) away from $origLat, $origLon in which to search
$query = "SELECT name, latitude, longitude, 3956 * 2 * 
          ASIN(SQRT( POWER(SIN(($origLat - latitude)*pi()/180/2),2)
          +COS($origLat*pi()/180 )*COS(latitude*pi()/180)
          *POWER(SIN(($origLon-longitude)*pi()/180/2),2))) 
          as distance FROM $tableName WHERE 
          longitude between ($origLon-$dist/cos(radians($origLat))*69) 
          and ($origLon+$dist/cos(radians($origLat))*69) 
          and latitude between ($origLat-($dist/69)) 
          and ($origLat+($dist/69)) 
          having distance < $dist ORDER BY distance limit 100"; 
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_assoc($result)) {
    echo $row['name']." > ".$row['distance']."<BR>";
}
mysql_close($db);
?>

./assets/db/db.php

<?PHP
/**
 * Class to initiate a new MySQL connection based on $dbInfo settings found in dbSettings.php
 *
 * @example $db = new database(); // Initiate a new database connection
 * @example mysql_close($db); // close the connection
 */
class database{
    protected $databaseLink;
    function __construct(){
        include "dbSettings.php";
        $this->database = $dbInfo['host'];
        $this->mysql_user = $dbInfo['user'];
        $this->mysql_pass = $dbInfo['pass'];
        $this->openConnection();
        return $this->get_link();
    }
    function openConnection(){
    $this->databaseLink = mysql_connect($this->database, $this->mysql_user, $this->mysql_pass);
    }

    function get_link(){
    return $this->databaseLink;
    }
}
?>

./assets/db/dbSettings.php

<?php
$dbInfo = array(
    'host'      => "localhost",
    'user'      => "root",
    'pass'      => "password"
);
?>

It may be possible to increase performance by using a MySQL stored procedure as suggested by the "Geo-Distance-Search-with-MySQL" article posted above.

I have a database of ~17,000 places and the query execution time is 0.054 seconds.

Community
  • 1
  • 1
circuitry
  • 1,169
  • 16
  • 16
  • How can I obtain the distance in Km or Meters? Regards! – chemitaxis Nov 21 '14 at 13:05
  • 2
    WARNING. Excelent solution, but it has a bug. All the `abs` should be removed. There is no need to take the abs value when converting from degrees to radians, and, even if you did, you are doing it to just one of the latitudes. Please edit it so it fixes the bug. – Chango Jan 12 '16 at 21:59
  • 1
    And for anyone who wants this in meters: Convert 3956 miles to kilometers: Earth's radius; Convert 69 miles to kilometers: the aproxímate length of 1 degree latitude in km; And input the distance in kilometers. – Chango Jan 13 '16 at 16:15
  • Should be able to exchange the `3956` with `6371` to have the results come up in km's as that is the earth's radius in KM's. – rkeet Apr 26 '16 at 10:17
  • 1
    And replace `69` with `111,044736` (forgot that in above comment) – rkeet Apr 26 '16 at 10:31
  • Hi, I just implemented your method for calculating distance. I would just like to know what is the margin of error in this formula? For example, for the same value of latitude and longitude I am getting a distance of 1.85 mile whereas it should be 0. – Sayantan Das Dec 05 '16 at 05:22
  • *"WARNING. Excelent solution, but it has a bug."* @Chango i know this is a old answer but when you see the possible SQL injection locations in this code you would/could not really worry about the `abs()` function. – Raymond Nijland May 03 '19 at 23:50
  • The scribd link is now behind a paywall. Better to link to the source, which has been updated from time to time: http://www.arubin.org/files/geo_search.pdf – Martijn Pieters Feb 25 '20 at 08:06
  • This worked for me and i tried lots solutions but this one save my day. Thank you – Sasindu Jayampathi Jul 10 '21 at 04:42
27

Just in case you are lazy like me, here's a solution amalgamated from this and other answers on SO.

set @orig_lat=37.46; 
set @orig_long=-122.25; 
set @bounding_distance=1;

SELECT
*
,((ACOS(SIN(@orig_lat * PI() / 180) * SIN(`lat` * PI() / 180) + COS(@orig_lat * PI() / 180) * COS(`lat` * PI() / 180) * COS((@orig_long - `long`) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance` 
FROM `cities` 
WHERE
(
  `lat` BETWEEN (@orig_lat - @bounding_distance) AND (@orig_lat + @bounding_distance)
  AND `long` BETWEEN (@orig_long - @bounding_distance) AND (@orig_long + @bounding_distance)
)
ORDER BY `distance` ASC
limit 25;
Evan
  • 3,191
  • 4
  • 29
  • 25
  • 1
    what exactly does `bounding_distance` represent? does this value limit the results to a mile amount? so in this case it will return results within 1 mile? – james Nov 14 '12 at 14:43
  • 1
    @ bounding_distance is in degrees here, and is used to speed up calculations by limiting the effective search region. For example, if you know your user is in a certain city, and you know you have a few points within that city, you can safely set your bounding distance to a few degrees. – Evan Nov 14 '12 at 16:22
  • 1
    Which geographical distance formula is this using? – bbodenmiller Aug 19 '15 at 08:08
  • The "bounding box" is being used in the `WHERE` to make it possible to use `INDEX(lat, lng), INDEX(lng, lat)`, but it is sub-optimal because `@bounding_distance` needs to be adjusted by dividing by `COS(@orig_lat)`. – Rick James Jun 05 '21 at 18:24
13

Easy one ;)

SELECT * FROM `WAYPOINTS` W ORDER BY
ABS(ABS(W.`LATITUDE`-53.63) +
ABS(W.`LONGITUDE`-9.9)) ASC LIMIT 30;

Just replace the coordinates with your required ones. The values have to be stored as double. This ist a working MySQL 5.x example.

Cheers

Nicholas
  • 163
  • 1
  • 2
7

Try this, it show the nearest points to provided coordinates (within 50 km). It works perfectly:

SELECT m.name,
    m.lat, m.lon,
    p.distance_unit
             * DEGREES(ACOS(COS(RADIANS(p.latpoint))
             * COS(RADIANS(m.lat))
             * COS(RADIANS(p.longpoint) - RADIANS(m.lon))
             + SIN(RADIANS(p.latpoint))
             * SIN(RADIANS(m.lat)))) AS distance_in_km
FROM <table_name> AS m
JOIN (
      SELECT <userLat> AS latpoint, <userLon> AS longpoint,
             50.0 AS radius, 111.045 AS distance_unit
     ) AS p ON 1=1
WHERE m.lat
BETWEEN p.latpoint  - (p.radius / p.distance_unit)
    AND p.latpoint  + (p.radius / p.distance_unit)
    AND m.lon BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
    AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
ORDER BY distance_in_km

Just change <table_name>. <userLat> and <userLon>

You can read more about this solution here: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

smartmouse
  • 13,912
  • 34
  • 100
  • 166
5

You're looking for things like the haversine formula. See here as well.

There's other ones but this is the most commonly cited.

If you're looking for something even more robust, you might want to look at your databases GIS capabilities. They're capable of some cool things like telling you whether a point (City) appears within a given polygon (Region, Country, Continent).

Community
  • 1
  • 1
Koobz
  • 6,928
  • 6
  • 41
  • 53
  • It is indeed the most cited, but many articles refer to old computing hardware when it comes to statements about inaccurate computing using other methods. See also http://www.movable-type.co.uk/scripts/latlong.html#cosine-law – Arjan May 29 '10 at 17:04
4

Check this code based on the article Geo-Distance-Search-with-MySQL:

Example: find the 10 nearest hotels to my current location in a 10 miles radius:

#Please notice that (lat,lng) values mustn't be negatives to perform all calculations

set @my_lat=34.6087674878572; 
set @my_lng=58.3783670308302;
set @dist=10; #10 miles radius

SELECT dest.id, dest.lat, dest.lng,  3956 * 2 * ASIN(SQRT(POWER(SIN((@my_lat -abs(dest.lat)) * pi()/180 / 2),2) + COS(@my_lat * pi()/180 ) * COS(abs(dest.lat) *  pi()/180) * POWER(SIN((@my_lng - abs(dest.lng)) *  pi()/180 / 2), 2))
) as distance
FROM hotel as dest
having distance < @dist
ORDER BY distance limit 10;

#Also notice that distance are expressed in terms of radius.
4

Find nearest Users to my:

Distance in meters

Based in Vincenty's formula

i have User table:

+----+-----------------------+---------+--------------+---------------+
| id | email                 | name    | location_lat | location_long |
+----+-----------------------+---------+--------------+---------------+
| 13 | xxxxxx@xxxxxxxxxx.com | Isaac   | 17.2675625   | -97.6802361   |
| 14 | xxxx@xxxxxxx.com.mx   | Monse   | 19.392702    | -99.172596    |
+----+-----------------------+---------+--------------+---------------+

sql:

-- my location:  lat   19.391124   -99.165660
SELECT 
(ATAN(
    SQRT(
        POW(COS(RADIANS(users.location_lat)) * SIN(RADIANS(users.location_long) - RADIANS(-99.165660)), 2) +
        POW(COS(RADIANS(19.391124)) * SIN(RADIANS(users.location_lat)) - 
       SIN(RADIANS(19.391124)) * cos(RADIANS(users.location_lat)) * cos(RADIANS(users.location_long) - RADIANS(-99.165660)), 2)
    )
    ,
    SIN(RADIANS(19.391124)) * 
    SIN(RADIANS(users.location_lat)) + 
    COS(RADIANS(19.391124)) * 
    COS(RADIANS(users.location_lat)) * 
    COS(RADIANS(users.location_long) - RADIANS(-99.165660))
 ) * 6371000) as distance,
users.id
FROM users
ORDER BY distance ASC

radius of the earth : 6371000 ( in meters)

Isaac Limón
  • 1,940
  • 18
  • 15
3
simpledb.execSQL("CREATE TABLE IF NOT EXISTS " + tablename + "(id INTEGER PRIMARY KEY   AUTOINCREMENT,lat double,lng double,address varchar)");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2891001','70.780154','craftbox');");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2901396','70.7782428','kotecha');");//22.2904718 //70.7783906
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2863155','70.772108','kkv Hall');");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.275993','70.778076','nana mava');");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2667148','70.7609386','Govani boys hostal');");


    double curentlat=22.2667258;  //22.2677258
    double curentlong=70.76096826;//70.76096826

    double curentlat1=curentlat+0.0010000;
    double curentlat2=curentlat-0.0010000;

    double curentlong1=curentlong+0.0010000;
    double curentlong2=curentlong-0.0010000;

    try{

        Cursor c=simpledb.rawQuery("select * from '"+tablename+"' where (lat BETWEEN '"+curentlat2+"' and '"+curentlat1+"') or (lng BETWEEN         '"+curentlong2+"' and '"+curentlong1+"')",null);

        Log.d("SQL ", c.toString());
        if(c.getCount()>0)
        {
            while (c.moveToNext())
            {
                double d=c.getDouble(1);
                double d1=c.getDouble(2);

            }
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
Hardip
  • 360
  • 3
  • 9
2

It sounds like you want to do a nearest neighbour search with some bound on the distance. SQL does not support anything like this as far as I am aware and you would need to use an alternative data structure such as an R-tree or kd-tree.

Chris de Vries
  • 56,777
  • 5
  • 32
  • 27
2

MS SQL Edition here:

        DECLARE @SLAT AS FLOAT
        DECLARE @SLON AS FLOAT

        SET @SLAT = 38.150785
        SET @SLON = 27.360249

        SELECT TOP 10 [LATITUDE], [LONGITUDE], SQRT(
            POWER(69.1 * ([LATITUDE] - @SLAT), 2) +
            POWER(69.1 * (@SLON - [LONGITUDE]) * COS([LATITUDE] / 57.3), 2)) AS distance
        FROM [TABLE] ORDER BY 3
B.Tekkan
  • 570
  • 4
  • 7
1

Sounds like you should just use PostGIS, SpatialLite, SQLServer2008, or Oracle Spatial. They can all answer this question for you with spatial SQL.

TheSteve0
  • 3,530
  • 1
  • 19
  • 25
  • 10
    sounds like you should just NOT suggest that people switch their entire database platform and cause irrelevant results to show up in my google search when i explicitly search fro "Oracle"... – I wrestled a bear once. Jun 02 '16 at 20:29
1
 +----+-----------------------+---------+--------------+---------------+
| id | email                 | name    | location_lat | location_long |
+----+-----------------------+---------+--------------+---------------+
| 7  | test@gmail.com        | rembo   | 23.0249256   |  72.5269697   |
| 25 | test1@gmail.com.      | Rajnis  | 23.0233221    | 72.5342112   |
+----+-----------------------+---------+--------------+---------------+

$lat = 23.02350629;

$long = 72.53230239;

DB:: SELECT (" SELECT * FROM ( SELECT , ( ( ( acos( sin(( ". $ lat ." * pi() / 180)) * sin(( lat * pi() / 180)) + cos(( ". $ lat ." pi() / 180 )) * cos(( lat * pi() / 180)) * cos((( ". $ long ." - LONG) * pi() / 180))) ) * 180 / pi() ) * 60 * 1.1515 * 1.609344 ) as distance FROM users ) users WHERE distance <= 2");

  • 1
    You could format the query to improve readability. Also, when pasting code use the appropriate tags so it´s displayed correctly. – Curious Mind Oct 09 '20 at 14:45
  • It would be nice if you could explain what is going on here aswell. Like this is just a copy-pasted answer – Diego Oct 09 '20 at 15:35
0

In extreme cases this approach fails, but for performance, I've skipped the trigonometry and simply calculated the diagonal squared.

user1032402
  • 410
  • 1
  • 3
  • 11
-1

Mysql query for search coordinates with distance limit and where condition

 SELECT id, ( 3959 * acos( cos( radians('28.5850154') ) * cos( radians(latitude) ) * cos( radians( longitude ) - radians('77.07207489999999') ) + sin( radians('28.5850154') ) * sin( radians( latitude ) ) ) ) AS distance FROM `vendors` HAVING distance < 5;
-22

This problem is not very hard at all, but it gets more complicated if you need to optimize it.

What I mean is, do you have 100 locations in your database or 100 million? It makes a big difference.

If the number of locations is small, get them out of SQL and into code by just doing ->

Select * from Location

Once you get them into code, calculate the distance between each lat/lon and your original with the Haversine formula and sort it.

chamiltongt
  • 152
  • 3