PHP/MySQL:从数据库中选择距离给定位置较近的位置

8
在PHP中,我有以下代码用于计算两个位置之间的距离:
<?php
function distance($lat1, $long1, $lat2, $long2) {
    // DEGREE TO RADIAN
    $latitude1 = $lat1/180*pi();
    $longitude1 = $long1/180*pi();
    $latitude2 = $lat2/180*pi();
    $longitude2 = $long2/180*pi();
    // FORMULA: e = ARCCOS ( SIN(Latitude1) * SIN(Latitude2) + COS(Latitude1) * COS(Latitude2) * COS(Longitude2-Longitude1) ) * EARTH_RADIUS
    $distance = acos(sin($latitude1)*sin($latitude2)+cos($latitude1)*cos($latitude2)*cos($longitude2-$longitude1))*6371;
    return $distance;
}
echo distance(9.9921962, 53.5534074, 9.1807688, 48.7771056); // Hamburg, DE - Stuttgart, DE
?>

现在,我想通过PHP从我的MySQL数据库中选择靠近给定位置的地点:

  • 用户输入他的家乡
  • 我的脚本通过Google API获取纬度/经度值
  • 在我的数据库中,我有大约200个地点,每个地点都有一个纬度值和一个经度值字段
  • 我需要编写PHP和MySQL代码来选择离用户家乡最近的10个地点

希望你能帮助我。提前感谢!

7个回答

8

谢谢,正如nOw2所说,这是Haversine公式。我已经有PHP实现了,在我的问题中可以看到代码。 - caw

4
也许类似以下内容:
SELECT field1, field2, ...,
    ACOS(SIN(latitude / 180 * PI()) * SIN(:1) + COS(latitude / 180 * PI()) * COS(:2) * COS(:2 - longtidude)) * 6371 AS distance
    ORDER BY distance ASC;

或者

SELECT field1, field2, ...,
    ACOS(SIN(RADIANS(latitude)) * SIN(:1) + COS(RADIANS(latitude)) * COS(:2) * COS(:2 - longtidude)) * 6371 AS distance
    ORDER BY distance ASC;

这段代码直接翻译过来的意思是:

:1:2 分别是 $lat2/180*pi()$long2/180*pi()


谢谢,这和nOw2的答案一样,对吧?你写的是"$lat2/180*pi()"。为什么不直接用"RADIANS($lat2)"呢?既然在查询的其他部分中都使用了它,那么为什么这里也不用呢? - caw
:1和:2来自于PHP,它没有弧度制。不过可以使用http://us2.php.net/deg2rad。 - itsbth

1

这是Haversine公式。您可以直接将PHP翻译成SQL,以便在空间上查询数据库(另一种选择是从数据库中提取每个记录并通过PHP运行数据)。MySQL提供了您需要的所有数学函数。

我为一个商业网站做过这个,该网站提供基于邮政编码的距离查找,因此没有特定的GIS功能也可以实现。


谢谢,它很好用! :) 我不知道MySQL拥有所有的数学函数。 - caw

0

刚看到这个话题。也许有人会对这个函数感兴趣,在MySql 5.7中已经测试过:

    create function GetDistance(lat1 real, lng1 real, lat2 real, lng2 real) returns real no sql
    return ATAN2(SQRT(POW(COS(RADIANS(lat2)) * SIN(RADIANS(lng1 - lng2)), 2) + 
                POW(COS(RADIANS(lat1)) * SIN(RADIANS(lat2)) - SIN(RADIANS(lat1)) *
                COS(RADIANS(lat2)) *  COS(RADIANS(lng1 - lng2)), 2)), 
                (SIN(RADIANS(lat1)) * SIN(RADIANS(lat2)) + COS(RADIANS(lat1)) *
                COS(RADIANS(lat2)) * COS(RADIANS(lng1 - lng2)))) * 6372.795;

调用:

select GetDistance(your_latitude, your_longitude, table_field_lat,
                   table_field_lng) as dist from [your_table] limit 5;

0

谢谢,但我不能使用MySQL的地理空间功能。 - caw

0

MySQL 具有对行进行地理空间索引的能力。您可能不需要自己计算这些数学问题(您可以要求 MySQL 计算两个地理对象之间的距离并按此排序..)。

请参见:http://forums.mysql.com/read.php?23,159205,159205


谢谢,但我不能使用MySQL的地理空间特性。 - caw

-1

谢谢!我已经在我的数据库中有了数据,所以不需要使用GeoNames的API。 - caw
是的,我明白,但你可以将那200条记录与Geonames的响应进行匹配,然后从中找出最接近的10个匹配项。这再次假设你的200条记录是某些已知地点而不是随机位置。 - mr-euro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接