按计算距离对 MySQL 结果排序(距离未存储在 DB 中)
Posted
技术标签:
【中文标题】按计算距离对 MySQL 结果排序(距离未存储在 DB 中)【英文标题】:Sorting MySQL results by calculated distance (distance not stored in DB) 【发布时间】:2015-09-13 22:19:17 【问题描述】:我将“地点”存储在数据库中,我正在使用 php 来访问它们。我想要做的是返回所有按相对于某个地方的距离排序的地方。
这个地点将是来自 android 应用程序的动态,即我想显示最接近用户位置的所有地点。
最好的方法是什么?将PHP中的所有位置检索到一个数组中,计算每个位置的距离,然后按距离对该数组进行排序是否有效/高效?或者有没有更简单/更快的方法来完成我的需要?
谢谢!
【问题讨论】:
【参考方案1】:您可以在 SQL 中通过即时计算距离来完成这一切。这是存储的lat
/lon
字段与提供的$lat
/$lon
之间距离的粗略近似值。
$dlat = "(`lat`-$lat)";
$dlon = "(`lon`-$lon)*".cos($lat*3.1415/180);
$dist_sql = "$dlat*$dlat+$dlon*$dlon";
$sql = "IF(`lat` IS NULL,1e20,$dist_sql)";
然后像使用任何其他字段一样使用$sql
,例如
SELECT * FROM `table` ORDER BY $sql ASC
这远非完美,但至少可以帮助您入门。
cos()
之所以出现,是因为随着(绝对)纬度的增加,经度的一个度数会缩短距离。
要从$sql
得到以公里为单位的实际值,除以 90 并乘以 10000 公里。 (再次:非常粗略的近似值!)
【讨论】:
太棒了!谢谢,不知道这可以在 SQL 中完成。我希望有更好的方法。谢谢你的开始,我会努力的。【参考方案2】:如果数据库中的每个位置都有纬度/经度字段,则在数据库中进行距离计算。以下存储过程需要进行一些调整以适合您的数据库,因为我们不知道架构 - 但它假定一个名为 places
的表具有一个包含位置纬度的字段和一个包含经度的字段。
CREATE PROCEDURE `spNearestPlaces`(IN `_latitude` double, IN `_longitude` double, IN `_radius` INT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
proc:begin
declare strsql varchar(10000);
declare lat double default 0;
declare lng double default 0;
declare radius float default 0;
declare earth_radius integer default 0;
declare lon1 float;
declare lat1 float;
declare lon2 float;
declare lat2 float;
set @lat=_latitude;
set @lng=_longitude;
set @radius=cast(_radius as unsigned);
set @earth_radius=3956;
set @lon1 = @lng - @radius/ceil( cos( radians( @lat ) ) * 69 );
set @lon2 = @lng + @radius/ceil( cos( radians( @lat ) ) * 69 );
set @lat1 = @lat - ( @radius/69 );
set @lat2 = @lat + ( @radius/69 );
set @strsql=concat("select
p.`id`,
p.`latitude`,
p.`longitude`,
ROUND( @earth_radius * 2 * ASIN( SQRT( POWER( SIN( (@lat - p.`latitude`) * pi()/180 / 2), 2) +COS(@lat * pi()/180) * COS(p.`latitude` * pi()/180) *POWER(SIN((@lng - p.`longitude`) * pi()/180 / 2), 2) ) ),2) AS 'distance'
from `places` p
where
p.`latitude` between @lat1 and @lat2
and
p.`longitude` between @lon1 and @lon2
having `distance` <= @radius
order by `distance`;");
prepare stmt from @strsql;
execute stmt;
deallocate prepare stmt;
end
你会从 php 调用存储过程,例如:-
$lat=56.564;
$lng=-2.5465;
$radius=5;
call `spNearestPlaces`($lat,$lng,$radius);
【讨论】:
太棒了,谢谢,我会检查一下。截至目前,我的桌子没有纬度/经度,但如果需要,我可以轻松添加这些以上是关于按计算距离对 MySQL 结果排序(距离未存储在 DB 中)的主要内容,如果未能解决你的问题,请参考以下文章
mysql 下 计算 两点 经纬度 之间的距离 计算结果排序