php - 按纬度/经度对 MySQL 查询进行排序

标签 php mysql

我数据库中的每个用户都将他们的纬度和经度存储在两个字段(纬度,经度)中

每个字段的格式为:

lon | -1.403976 
lat | 53.428691

如果用户在 100 英里范围内搜索其他用户,我会执行以下操作以计算适当的纬度/经度范围($lat 和 $lon 是当前用户值)

$R = 3960;  // earth's mean radius
$rad = '100';
// first-cut bounding box (in degrees)
$maxLat = $lat + rad2deg($rad/$R);
$minLat = $lat - rad2deg($rad/$R);
// compensate for degrees longitude getting smaller with increasing latitude
$maxLon = $lon + rad2deg($rad/$R/cos(deg2rad($lat)));
$minLon = $lon - rad2deg($rad/$R/cos(deg2rad($lat)));

$maxLat=number_format((float)$maxLat, 6, '.', '');
$minLat=number_format((float)$minLat, 6, '.', '');
$maxLon=number_format((float)$maxLon, 6, '.', '');
$minLon=number_format((float)$minLon, 6, '.', '');

然后我可以执行如下查询:

$query = "SELECT * FROM table WHERE lon BETWEEN '$minLon' AND '$maxLon' AND lat BETWEEN '$minLat' AND '$maxLat'";

这很好用,我在输出阶段使用一个函数来计算和显示用户之间的实际距离,但我希望能够在查询阶段通过减少或增加距离来对结果进行排序。

有什么办法吗?

最佳答案

还记得毕达哥拉斯吗?

$sql = "SELECT * FROM table 
    WHERE lon BETWEEN '$minLon' AND '$maxLon' 
      AND lat BETWEEN '$minLat' AND '$maxLat'
    ORDER BY (POW((lon-$lon),2) + POW((lat-$lat),2))";

从技术上讲,这是距离的平方,而不是实际距离,但因为您只是将它用于排序,所以没关系。

这使用了平面距离公式,这应该适用于小距离。

但是:

如果您想更精确或使用更长的距离,请使用 this formula for great circle distances in radians :

dist = acos[ sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lng1-lng2) ]

(要以实际单位而不是弧度获得距离,请将其乘以地球的半径。不过,这对于排序目的不是必需的。)

MySQL 计算引擎假定纬度和经度以弧度为单位,因此如果它以度为单位(可能是),您必须将每个值乘以 pi/180,大约为 0.01745:

$sf = 3.14159 / 180; // scaling factor
$sql = "SELECT * FROM table 
    WHERE lon BETWEEN '$minLon' AND '$maxLon' 
      AND lat BETWEEN '$minLat' AND '$maxLat'
    ORDER BY ACOS(SIN(lat*$sf)*SIN($lat*$sf) + COS(lat*$sf)*COS($lat*$sf)*COS((lon-$lon)*$sf))";

甚至:

$sf = 3.14159 / 180; // scaling factor
$er = 6350; // earth radius in miles, approximate
$mr = 100; // max radius
$sql = "SELECT * FROM table 
    WHERE $mr >= $er * ACOS(SIN(lat*$sf)*SIN($lat*$sf) + COS(lat*$sf)*COS($lat*$sf)*COS((lon-$lon)*$sf))
    ORDER BY ACOS(SIN(lat*$sf)*SIN($lat*$sf) + COS(lat*$sf)*COS($lat*$sf)*COS((lon-$lon)*$sf))";

关于php - 按纬度/经度对 MySQL 查询进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16465779/

相关文章:

php - 每隔几次访问就会超出 Laravel cookie 存储空间

php - IN 子句输出的重新排列

Mysql:如何优化这个查询。以获得更快的结果

php - 我如何构建 db_select, ->condition 将字段与 drupal 中的值与 php 进行比较

Mysql错误代码1452,两个表具有不同的数据库引擎

mysql - 选择除最近的四行之外的所有行

php - Twig 和 Symfony2 中的自定义反式过滤器

php PDO 和 mysql : how to insert a geo point type?

php - 需要在插入第一个表时更新第二个表

mysql - mySQL 批量更新速度太慢