Php 按计算距离对MySQL结果排序(距离不存储在DB中)

Php 按计算距离对MySQL结果排序(距离不存储在DB中),php,android,mysql,sorting,geolocation,Php,Android,Mysql,Sorting,Geolocation,我将“位置”存储在数据库中,并使用PHP访问它们。我要做的是返回所有按相对于某个位置的距离排序的位置 这个地方将是动态的Android应用程序,也就是说,我想显示所有最接近用户位置的地方 最好的方法是什么?将PHP中的所有位置检索到一个数组中,计算每个位置的距离,然后按距离对该数组排序是否有效?还是有更简单/更快的方法来完成我需要的 谢谢 您可以在SQL中通过动态计算距离来完成这一切。这是存储的lat/lon字段和提供的$lat/$lon $dlat = "(`lat`-$lat)"; $dlo

我将“位置”存储在数据库中,并使用PHP访问它们。我要做的是返回所有按相对于某个位置的距离排序的位置

这个地方将是动态的Android应用程序,也就是说,我想显示所有最接近用户位置的地方

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


谢谢

您可以在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中通过计算动态距离来完成所有操作。这是存储的
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中通过计算动态距离来完成所有操作。这是存储的
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中通过计算动态距离来完成所有操作。这是存储的
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公里。(同样:非常粗略的近似!)

如果数据库中的每个位置都有lat/lon字段,则在数据库中进行距离计算。下面的存储过程需要进行一些调整以适合您的db,因为我们不知道模式-但它假设一个名为
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

如果db中的每个位置都有lat/lon字段,则在db中进行距离计算。下面的存储过程需要进行一些调整以适合您的db,因为我们不知道模式-但它假设一个名为
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

如果db中的每个位置都有lat/lon字段,则在db中进行距离计算。下面的存储过程需要进行一些调整以适合您的db,因为我们不知道模式-但它假设一个名为
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

如果db中的每个位置都有lat/lon字段,则在db中进行距离计算。下面的存储过程需要进行一些调整以适合您的db,因为我们不知道模式-但它假设一个名为
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

令人惊叹的!谢谢,我不知道这可以用SQL完成。我希望有更好的办法。谢谢你的开始,我会努力的。太棒了!谢谢,我不知道这可以用SQL完成。我希望有更好的办法。谢谢你的开始,我会努力的。太棒了!谢谢,我不知道这可以用SQL完成。我希望有更好的办法。谢谢你的开始,我会努力的。太棒了!谢谢,我不知道这可以用SQL完成。我希望有更好的办法。谢谢你的开始,我会努力的。太棒了,谢谢,我会看看这个。到目前为止,我的表格没有Lat/Long,但如果需要,我可以轻松添加这些。谢谢,我会检查一下。到目前为止,我的表格没有Lat/Long,但如果需要,我可以轻松添加这些。谢谢,我会检查一下。到目前为止,我的表格没有Lat/Long,但如果需要,我可以轻松添加这些。谢谢,我会检查一下。到目前为止,我的表没有Lat/Long,但如果需要,我可以轻松地添加这些