У меня есть таблица (user_zip_codes) с zip_code, широтой и долготой пользователей. Я нашел функцию здесь в 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). Как мне настроить свой запрос, чтобы это произошло?
Заранее спасибо.
ОБНОВЛЕНИЕ: слово «расстояние» может показаться неоднозначным (благодаря Хорхе). Я просто хочу сортировать zip_codes по расстоянию, обозначенному как расстояние между двумя точками.
Вы можете использовать что-то вроде
$iDistance = 20; $iRadius = 6371; // earth radius in km $iRadius = 3958; // earth radius in miles $fLat = xy; // Your position latitude $fLon = xy; // 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";
где вам нужно получить значение lat / lon перед использованием SQL. Это работает для меня
ORDER BY (3958*3.1415926*sqrt((lat-$lat)*(lat-$lat) + cos(lat/57.29578)*cos($lat/57.29578)*(lon-$lon)*(lon-$lon))/180) DESC
MySQL имеет геометрические функции для вычисления расстояния. Однако вам нужно будет управлять вашими координатными парами как полями Point
вместо отдельных полей float. Обходным путем было бы превратить оба столбца в координатную пару.
$sql = "SELECT userID, city, zip_code, country, GeometryFromText( CONCAT( 'POINT(', lon, ' ', lat, ')' ) ) as coord FROM user_zip_codes ";
Если вместо точек вы используете переменные $ lat и $ lon для создания LineString
, yo может использовать 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";
Он все еще выглядит грязным. Должен быть способ объявить LineString без использования своего представления WKT. Я буду продолжать смотреть.