2015-09-13 44 views
0

我将“地点”存储在数据库中,并且正在使用PHP访问它们。我想要做的是返回按距离排序的所有地点相对于某个地方。按计算出的距离排序MySQL结果(未存储在数据库中的距离)

这个地方会从Android应用程序动态显示,即我想显示所有离用户位置最近的地方。

什么是做到这一点的最好方法是什么?将PHP中的所有位置检索到数组中,计算每个位置的距离,然后按距离对该数组进行排序会有效吗?还是有一种更简单/更快的方式来完成我所需要的?

谢谢!

回答

2

你可以在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获得以km为单位的实际值,除以90并乘以10000 km。 (再次:非常粗略的近似值!)

+0

真棒!谢谢,不知道这可以在SQL中完成。我希望有更好的办法。感谢你的开始,我会努力工作的。 – user1282637

0

如果数据库中的每个位置都有纬度/经度字段,则在数据库中进行距离计算。以下存储过程需要进行一些调整以适应您的数据库,因为我们不知道该模式 - 但它假定一个名为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); 
+0

太棒了,谢谢,我会检查一下。截至目前,我的桌子没有经纬度,但如果需要,我可以很容易地添加这些 – user1282637