【问题标题】:Querying MySQL for latitude and longitude coordinates that are within a given mile radius查询 MySQL 以获取给定英里半径内的纬度和经度坐标
【发布时间】:2015-06-15 17:27:52
【问题描述】:

我目前有一个结构如下的 MySQL 表:

id         name     lon            lat  
-----      -----    -----------    -----------
1          Mark     -76.316528     40.036027
2          John     -95.995102     41.25716
3          Paul     -82.337036     29.645095
4          Dave     -82.337036     29.645095
5          Chris    -76.316528     40.036027

我目前查询数据库以查看用户的位置是否在给定位置的特定英里半径内的方式是这样做。

function Haversine($lat_from, $lon_from, $lat_to, $lon_to) {
    $radius = 6371000;
    $delta_lat = deg2rad($lat_to-$lat_from);
    $delta_lon = deg2rad($lon_to-$lon_from);

    $a = sin($delta_lat/2) * sin($delta_lat/2) +
        cos(deg2rad($lat_from)) * cos(deg2rad($lat_to)) *
        sin($delta_lon/2) * sin($delta_lon/2);
    $c = 2*atan2(sqrt($a), sqrt(1-$a));

    // Convert the distance from meters to miles
    return ceil(($radius*$c)*0.000621371);
}

// Set the given location to NYC
$my_lon = -73.9844;
$my_lat = 40.7590;

// Query the DB for all of the users
$sql = "SELECT * FROM users";
$result = mysqli_query($con, $sql)or die(mysqli_error($con));
$count = mysqli_num_rows($result);
$i = 0;

while($row = mysqli_fetch_assoc($result)) {
    $lon[$i] = $row['lon'];
    $lat[$i] = $row['lat'];

    $i++;
}

for($i=0;$i<$count;$i++) {
    // Calculate the distance between each user's location and my location
    $distance = Haversine($my_lat, $my_lon, $lat[$i], $lon[$i);

    if($distance < 50) {
        echo "Close enough";
    }
}

这适用于表中只有几百行的情况。但是,现在我有数万行,检查这么多行已被证明非常耗时。我想知道是否有办法使用Haversine 公式仅查询半径 50 英里内的行。

【问题讨论】:

  • 如果您不需要精确的半径,只需计算一个边界框(左上角和右下角),您的位置位于中间,然后执行WHERE latitude BETWEEN $min AND $max 之类的操作。

标签: mysql sql geolocation haversine


【解决方案1】:

余弦公式的球面定律
(37和-122是你的半径中心的纬度和经度)

SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) 
    * cos( radians( long ) - radians(-122) ) + sin( radians(37) ) * sin(radians(lat)) ) ) AS distance 
FROM myTable
HAVING distance < 50
ORDER BY distance 

特点

  • 最快
  • 精度类似于 Harvesine 公式

Haversine 公式

SELECT id, 3959 * 2 * ASIN(SQRT(POWER(SIN((37 - abs(lat)) * pi()/180 / 2), 2)
       + COS(37 * pi()/180 ) * COS(abs(lat) * pi()/180)
       * POWER(SIN((-122 - long) * pi()/180 / 2), 2) )) as  distance
FROM myTable
HAVING distance < 50
ORDER BY distance

特点

  • 快速
  • 对浮点错误更加稳健

请注意,3959 是以英里为单位的地球半径。地球半径(公里):6371

您可以找到更多信息here

【讨论】:

  • 嗨,你能解释一下你是怎么得到 37, -122 的吗?我知道这是半径中心,但你是怎么得到这个数字的?您能否解释一下查询中的 lat 和 lon 代表什么?是您提供给查询的纬度、经度还是表中记录的纬度?
  • @Last_Node_Standing 37 和 -127 是圆的中心坐标。 50 是圆的半径
猜你喜欢
  • 1970-01-01
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
  • 2018-10-26
  • 1970-01-01
  • 2018-09-09
相关资源
最近更新 更多