【问题标题】:Sorting zip code proximity search by distance (php/mysql)按距离排序邮政编码邻近搜索(php/mysql)
【发布时间】:2014-07-14 11:52:09
【问题描述】:

我有一张表(user_zip_codes),上面有用户的邮政编码、纬度和经度。我在 stackoverflow 上找到了一个函数,可以找到特定半径内的邮政编码:

function zipcodeRadius($lat, $lon, $radius) {
    global $mysqli;
    $zipcodeList = array();
    $radius = ($radius ? $radius : 20);
    $sql = "SELECT userID,city,zip_code,country FROM user_zip_codes  WHERE (3958*3.1415926*sqrt((lat-$lat)*(lat-$lat) + cos(lat/57.29578)*cos($lat/57.29578)*(lon-$lon)*(lon-$lon))/180) <= $radius GROUP BY zip_code";
    if($stmt = $mysqli->prepare($sql)) {
        $stmt->execute();
        $stmt->bind_result($userID,$city,$zip_code,$country);
        while($stmt->fetch()) {
            $zipcodeList[] = array('userID'=>$userID,'city'=>$city,'zip_code'=>$zip_code,'country'=>$country);
        }
    }
    return $zipcodeList;
}

完美运行。但是,我希望函数按距离对数组进行排序(通过 ASC og DESC)。我应该如何调整我的查询才能发生这种情况?

提前致谢。

更新: “距离”这个词可能看起来模棱两可(感谢 Jorge)。我只是希望按距离对邮政编码进行排序,即两点之间的距离。

【问题讨论】:

  • “距离”这个词有点诡计。那是因为如果您的意思是基于两个点的距离或基于从第一个点和第二个点的道路的距离。你要哪一个?您应该使用此信息更新您的问题。
  • @JorgeCampos,我已经更新了我的问题。我的意思是基于两点的距离。
  • 在没有任何聚合函数的情况下,你不应该对任何东西进行分组!

标签: php mysql


【解决方案1】:

你可以使用类似的东西

$iDistance = 20;
$iRadius = 6371; // earth radius in km
$iRadius = 3958; // earth radius in miles
$fLat = x.y; // Your position latitude
$fLon = x.y; // Your position longitude

$strQuery = "
SELECT 
  *, 
  $iRadius * 2 * ASIN(SQRT(POWER(SIN(( $fLat - abs(pos.lat)) * pi() / 180 / 2),2) +
COS( $fLat * pi()/180) * COS(abs(pos.lat) * pi() / 180) * POWER(SIN(( $fLon - pos.lon) *
pi() / 180 / 2), 2) )) AS distance
FROM user_zip_codes pos
HAVING distance < $iDistance 
ORDER BY distance";

您必须在使用 SQL 之前获取您的纬度/经度值。这对我有用

【讨论】:

  • 为这个解决方案点赞,我实际上最终使用了它。它可以正确地对邮政编码进行分类,甚至可以轻松地在英里和公里之间切换。谢谢!
【解决方案2】:
ORDER BY (3958*3.1415926*sqrt((lat-$lat)*(lat-$lat) + cos(lat/57.29578)*cos($lat/57.29578)*(lon-$lon)*(lon-$lon))/180) DESC

【讨论】:

    【解决方案3】:

    MySQL 具有计算距离的几何函数。但是,您需要将坐标对作为 Point 字段而不是单独的浮点字段进行管理。一种解决方法是将两列都转换为坐标对。

    $sql = "SELECT userID,
                city,
                zip_code,
                country, 
                GeometryFromText( CONCAT( 'POINT(', lon, ' ', lat, ')' ) ) as coord
            FROM user_zip_codes  ";
    

    如果你使用 $lat 和 $lon 变量而不是点来投射 LineString,你可以使用 GLength 来获取距离

    $sql = "SELECT userID,
                    city,
                    zip_code,
                    country, 
                    GLength(GeomFromText(CONCAT('LineString(',lon,' ', lat1,',$lon $lat)'))) as distance
                FROM user_zip_codes  
                where GLength(GeomFromText(CONCAT('LineString(',lon,' ', lat1,',$lon $lat)')))<=$radius
                ORDER BY distance DESC";
    

    它看起来仍然很乱。应该有一种方法可以在不使用 WKT 表示的情况下声明 LineString。我会继续寻找。

    【讨论】:

    • 这太完美了,谢谢!我使用您的第二个示例与 $lat 和 $lon 来投射 LineString。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    相关资源
    最近更新 更多