使用mysql中的纬度和经度查找两点之间的距离

时间:2014-06-23 16:36:33

标签: mysql latitude-longitude

您好我有下表

 --------------------------------------------
 |  id  |  city  |  Latitude  |  Longitude  |
 --------------------------------------------
 |  1   |   3    |   34.44444 |   84.3434   |
 --------------------------------------------
 |  2   |   4    | 42.4666667 | 1.4666667   |
 --------------------------------------------
 |  3   |   5    |  32.534167 | 66.078056   |
 --------------------------------------------
 |  4   |   6    |  36.948889 | 66.328611   |
 --------------------------------------------
 |  5   |   7    |  35.088056 | 69.046389   |
 --------------------------------------------
 |  6   |   8    |  36.083056 |   69.0525   |
 --------------------------------------------
 |  7   |   9    |  31.015833 | 61.860278   |
 --------------------------------------------

现在我希望得到两点之间的距离。假设一个用户正在拥有一个城市3并且一个用户正在拥有一个城市7.我的场景是一个用户拥有一个城市,而latracy和longitude正在搜索其他用户与他的城市的距离。例如,具有城市3的用户正在搜索。他想让任何其他城市的用户距离说它是7.我搜索并发现以下查询

SELECT `locations`.`city`, ( 3959 * acos ( cos ( radians(31.589167) ) * cos( radians( Latitude ) ) * cos( radians( Longitude ) - radians(64.363333) ) + sin ( radians(31.589167) ) * sin( radians( Latitude ) ) ) ) AS `distance` FROM `locations` HAVING (distance < 50)

至于我知道这个查询找到从一个点到所有其他点的距离。现在我希望从一个点到另一个点的距离。

非常感谢任何指南。

7 个答案:

答案 0 :(得分:61)

我认为您的问题是,您希望计算距离的两个城市的city值。

此查询将为您完成工作,产生以km为单位的距离。它使用球面余弦定律公式。

请注意,您将表连接到自身,以便可以检索两个坐标对进行计算。

SELECT a.city AS from_city, b.city AS to_city, 
   111.111 *
    DEGREES(ACOS(LEAST(COS(RADIANS(a.Latitude))
         * COS(RADIANS(b.Latitude))
         * COS(RADIANS(a.Longitude - b.Longitude))
         + SIN(RADIANS(a.Latitude))
         * SIN(RADIANS(b.Latitude)), 1.0))) AS distance_in_km
  FROM city AS a
  JOIN city AS b ON a.id <> b.id
 WHERE a.city = 3 AND b.city = 7

请注意,常数111.1111是每纬度纬度的公里数,基于旧的拿破仑定量仪表作为从赤道到极点的距离的万分之一。这个定义足够接近定位器工作。

如果您需要法定里程而不是公里数,请改用69.0

http://sqlfiddle.com/#!2/abcc8/4/0

如果你正在寻找附近的点,你可能会想要使用这样的句子:

   HAVING distance_in_km < 10.0    /* slow ! */
    ORDER BY distance_in_km DESC

那就是(正如我们在美国波士顿附近所说的那样)邪恶缓慢。

在这种情况下,您需要使用边界框计算。请参阅此文章,了解如何执行此操作。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

答案 1 :(得分:16)

您可以使用ST_Distance_Sphere MySql内置函数。 它可以更有效地计算以米为单位的距离。

自MySql 5.7及更高版本开始受支持。

    select ST_Distance_Sphere(
    point(-87.6770458, 41.9631174),
    point(-73.9898293, 40.7628267)) 

引自Calculating distance using MySQL

答案 2 :(得分:4)

Heres是MySQL查询和函数,它用于获取两个纬度和经度之间的距离,距离将以KM返回。

Mysql查询: -

SELECT (6371 * acos( 
                cos( radians(lat2) ) 
              * cos( radians( lat1 ) ) 
              * cos( radians( lng1 ) - radians(lng2) ) 
              + sin( radians(lat2) ) 
              * sin( radians( lat1 ) )
                ) ) as distance from your_table

Mysql功能: -

DELIMITER $$
CREATE FUNCTION `getDistance`(`lat1` VARCHAR(200), `lng1` VARCHAR(200), `lat2` VARCHAR(200), `lng2` VARCHAR(200)) RETURNS varchar(10) CHARSET utf8
begin
declare distance varchar(10);

set distance = (select (6371 * acos( 
                cos( radians(lat2) ) 
              * cos( radians( lat1 ) ) 
              * cos( radians( lng1 ) - radians(lng2) ) 
              + sin( radians(lat2) ) 
              * sin( radians( lat1 ) )
                ) ) as distance); 

if(distance is null)
then
 return '';
else 
return distance;
end if;
end$$
DELIMITER ;

如何在PHP代码中使用

SELECT getDistance(lat1,lng1,$lat2,$lng2) as distance 
FROM your_table.

答案 3 :(得分:3)

不确定您的距离计算是如何进行的,但您需要对表进行self join并相应地执行计算。这样的事可能

select t1.id as userfrom, 
t2.id as userto, 
( 3959 * acos ( cos ( radians(31.589167) ) * cos( radians( t1.Latitude ) ) * 
cos( radians( t1.Longitude ) - radians(64.363333) ) + sin ( radians(31.589167) ) * 
sin( radians( t2.Latitude ) ) ) ) AS `distance` 
from table1 t1 
inner join table1 t2 on t2.city > t1.city

答案 4 :(得分:3)

这是一个MySQL函数,它将采用两个纬度/经度对,并给出两点之间的度数距离。它使用Haversine公式计算距离。由于地球不是一个完美的球体,在极地和赤道附近会有一些误差。

  • 要转换为里程,请乘以3961.
  • 要转换为公里数,请乘以6373。
  • 要转换为米,请乘以6373000。
  • 要转换为英尺,请乘以(3961 * 5280)20914080。
DELIMITER $$

CREATE FUNCTION \`haversine\`(

        lat1 FLOAT, lon1 FLOAT,
        lat2 FLOAT, lon2 FLOAT
     ) RETURNS float
    NO SQL
    DETERMINISTIC
    COMMENT 'Returns the distance in degrees on the Earth between two known points of latitude and longitude. To get miles, multiply by 3961, and km by 6373'

BEGIN

    RETURN DEGREES(ACOS(
              COS(RADIANS(lat1)) *
              COS(RADIANS(lat2)) *
              COS(RADIANS(lon2) - RADIANS(lon1)) +
              SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))
            ));

END;

DELIMITER;

答案 5 :(得分:1)

这是我从https://www.geodatasource.com/developers/javascript

转换而来的公式

这是一个很好的清洁功能,以KM计算距离

DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `FN_GET_DISTANCE`(
lat1 DOUBLE, lng1 DOUBLE, lat2 DOUBLE, lng2 DOUBLE
) RETURNS double
BEGIN
    DECLARE radlat1 DOUBLE;
    DECLARE radlat2 DOUBLE;
    DECLARE theta DOUBLE;
    DECLARE radtheta DOUBLE;
    DECLARE dist DOUBLE;
    SET radlat1 = PI() * lat1 / 180;
    SET radlat2 = PI() * lat2 / 180;
    SET theta = lng1 - lng2;
    SET radtheta = PI() * theta / 180;
    SET dist = sin(radlat1) * sin(radlat2) + cos(radlat1) * cos(radlat2) * cos(radtheta);
    SET dist = acos(dist);
    SET dist = dist * 180 / PI();
    SET dist = dist * 60 * 1.1515;
    SET dist = dist * 1.609344;
RETURN dist;
END$$
DELIMITER ;

您还可以在网站上找到不同语言的相同功能;

答案 6 :(得分:1)

重要!将计算传递给least(1.0, (...))函数时,使用或复制这些计算的任何人都必须使用acos()acos()函数的值不会大于1,我发现在比较相同的经/纬度值时,有时会得出类似1.000002的计算结果。这将产生NULL而不是0的距离,并且可能不会返回您要查找的结果,这取决于查询的结构!

这是正确的:

select round( 
  ( 3959 * acos( least(1.0,  
    cos( radians(28.4597) ) 
    * cos( radians(lat) ) 
    * cos( radians(lng) - radians(77.0282) ) 
    + sin( radians(28.4597) ) 
    * sin( radians(lat) 
  ) ) ) 
), 1) as distance
from locations having distance <= 60 order by distance

这是错误的:

select round( 
  ( 3959 * acos( 
    cos( radians(28.4597) ) 
    * cos( radians(lat) ) 
    * cos( radians(lng) - radians(77.0282) ) 
    + sin( radians(28.4597) ) 
    * sin( radians(lat) 
  ) ) 
), 1) as distance
from locations having distance <= 60 order by distance

评价最高的答案也谈到了这一点,但是我想确保这一点很明确,因为我刚刚在查询中发现了一个长期存在的错误。