按计算的距离(未存储在DB中的距离)对MySQL结果进行排序

时间:2015-09-13 22:19:17

标签: php android mysql sorting geolocation

我有"地方"存储在数据库中,我使用PHP来访问它们。我想要做的是返回按距离相对于某个地方排序的所有地方。

这个地方将是Android应用程序的动态,即我想显示距离用户最近的所有地方。

最好的方法是什么?将PHP中的所有位置检索到数组中,计算每个位置的距离,然后按距离对该数组进行排序是否有效/高效?或者是否有更简单/更快捷的方式来完成我需要的工作?

谢谢!

2 个答案:

答案 0 :(得分: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。 (再次:非常粗略的近似!)

答案 1 :(得分:0)

如果db中的每个位置都有lat / lon字段,那么在db中进行距离计算。以下存储过程需要进行一些调整以适应您的数据库,因为我们不知道模式 - 但它假设一个名为places的表,其中包含一个具有位置纬度的字段和一个具有经度的字段。 / p>

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