【问题标题】:PHP/MySQL: Select locations close to a given location from DBPHP/MySQL:从数据库中选择靠近给定位置的位置
【发布时间】:2010-10-28 00:57:24
【问题描述】:

在 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 个位置

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

【问题讨论】:

    标签: php mysql geolocation distance geography


    【解决方案1】:

    MySQL Great Circle Distance (Haversine formula) 完全满足您的需求。

    只有 200 条记录,但您也可以将它们全部加载并用代码检查它们。数据集真的太小了,不用担心数据库与代码或任何其他此类优化。

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

    Geo Proximity Search 与您遇到的问题几乎完全相同。

    【讨论】:

    • 谢谢,正如 nOw2 所说,这是 Haversine 公式。我已经实现了 PHP,请参阅我的问题中的代码。
    【解决方案2】:

    可能是这样的

    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()

    【讨论】:

    • 谢谢,和nOw2的回答一样,不是吗?你写“$lat2/180*pi()”。为什么不只是“RADIANS($lat2)”?您在查询的其余部分中使用了它,那么为什么不在这里呢?
    • :1 和 :2 来自没有 RADIANS 的 PHP。 us2.php.net/deg2rad 可以使用。
    【解决方案3】:

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

    我是为一个提供基于邮政/邮政编码的距离查找的商业网站执行此操作的,因此在没有特定 GIS 功能的情况下当然可以。

    【讨论】:

    • 谢谢,它工作正常! :) 我不知道 MySQL 有所有的数学函数。
    【解决方案4】:

    有一些 MySQL 函数可用于执行此操作。

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

    【讨论】:

    • 谢谢,但我不能使用 MySQL 的地理空间功能。
    【解决方案5】:

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

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

    【讨论】:

    • 谢谢,但我不能使用 MySQL 的地理空间功能。
    【解决方案6】:

    刚刚跨过这个话题。也许有人会对这个功能感兴趣,在 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;
    

    【讨论】:

      【解决方案7】:

      为什么不使用 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

      【讨论】:

      • 谢谢!我的数据库中有数据,所以我不需要使用 GeoNames 的 API。
      • 是的,我明白了,但是您可以将这 200 条记录与 Geonames 的响应相匹配,并从中找到 10 个最接近的匹配项。这再次假设您的 200 条记录是以某种方式已知的地方,而不是一些随机位置。
      猜你喜欢
      • 2022-07-06
      • 1970-01-01
      • 2012-05-13
      • 2016-07-28
      • 1970-01-01
      • 2014-04-25
      • 1970-01-01
      • 1970-01-01
      • 2010-12-05
      相关资源
      最近更新 更多