PHP / MySQL:从DB中选择靠近给定位置的位置

时间:2009-05-21 19:36:04

标签: php mysql geolocation distance geography

在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
?>

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

  • 用户进入家乡
  • 我的脚本通过Google API获取纬度/经度值
  • 在我的数据库中,我有大约200个位置,其中包含纬度值字段和经度值字段
  • 我需要一个PHP和MySQL代码来选择最接近用户家乡的10个位置

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

7 个答案:

答案 0 :(得分:8)

MySQL Great Circle Distance (Haversine formula)完全符合您的需要。

只有200条记录,但您也可以只加载它们并使用代码检查它们。数据集实际上太小了,不能过多地担心数据库与代码或任何其他此类优化。

Calculating distance between zip codes in PHP有几个这种算法的PHP实现。

Geo Proximity Search几乎就是你遇到的完全相同的问题。

答案 1 :(得分: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;

(直接从PHP代码翻译)

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

答案 2 :(得分:1)

那是Haversine公式。您可以将PHP直接转换为SQL,这样您就可以在空间上查询数据库(另一种方法是从数据库中提取每条记录并通过PHP运行数据)。 MySQL提供了您需要的所有数学函数。

我这样做是为了提供基于邮政编码/邮政编码的远程查询的商业网站,所以它当然没有特定的GIS功能。

答案 3 :(得分:0)

可以使用MySQL函数来完成此操作。

http://dev.mysql.com/doc/refman/5.0/en/gis-introduction.html

答案 4 :(得分:0)

MySQL能够对地理空间的行进行索引。您可能不需要自己做这个数学运算(您可以让MySQL计算两个地理对象之间的距离并按此排序......)。

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

答案 5 :(得分: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;

答案 6 :(得分:-1)

为什么不使用MySQL的地理空间功能......?不,开个玩笑。

如果200条记录是城镇等实际地方,那么您可以使用GeoNames的API吗?

以下网络服务将提供最接近lat和lng的10个位置:

http://ws.geonames.org/findNearby?lat=47.3&lng=9

来源:http://www.geonames.org/export/web-services.html#findNearbyPlaceName

完整列表:http://www.geonames.org/export/ws-overview.html