我有$latitude = 29.6815400
和$longitude = 64.3647100
,现在在MySQL中,我想采取15个最接近这些坐标的地方,我计划做这个查询:
SELECT *
FROM places
WHERE latitude BETWEEN($latitude - 1, $latitude + 1)
AND longitude BETWEEN($longitude - 1, $logintude + 1)
LIMIT 15;
你认为这是正确的还是你有其他的建议?
如何做BEETWEEN
,因为我想通过最大50Km范围搜索附近的地方?
我忘了说,我也可以使用PHP做任何之前运行查询。
注意:我不能使用存储过程
这里是PHP计算两点之间距离的公式:
function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'Mi')
{
$theta = $longitude1 - $longitude2;
$distance = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))+
(cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$distance = acos($distance); $distance = rad2deg($distance);
$distance = $distance * 60 * 1.1515;
switch($unit)
{
case 'Mi': break;
case 'Km' : $distance = $distance * 1.609344;
}
return (round($distance,2));
}
,然后添加一个查询来获取距离小于或等于上面那个的所有记录:
$qry = "SELECT *
FROM (SELECT *, (((acos(sin((".$latitude."*pi()/180)) *
sin((`geo_latitude`*pi()/180))+cos((".$latitude."*pi()/180)) *
cos((`geo_latitude`*pi()/180)) * cos(((".$longitude."-
`geo_longitude`)*pi()/180))))*180/pi())*60*1.1515*1.609344)
as distance
FROM `ci_geo`)myTable
WHERE distance <= ".$distance."
LIMIT 15";
,您可以在这里查看类似的计算。
你可以在这里阅读更多
更新:
你必须记住,要计算经度2和经度2你需要知道:
纬度的每度距离约为69英里(111公里)。这个范围从赤道的68.703英里(110.567公里)到两极的69.407英里(111.699公里)不等(由于地球的稍微椭球形状)。这很方便,因为每分钟(1/60度)大约是一英里。1度经度在赤道处最宽,为69.172英里(111.321),在两极处逐渐缩小至零。在北纬40度或南纬40度处,经度之间的距离为53英里(85公里)。
则按50km计算$longitude2 $latitude2
,则近似为
$longitude2 = $longitude1 + 0.449; //0.449 = 50km/111.321km
$latitude2 = $latitude1 + 0.450; // 0.450 = 50km/111km
作为经验法则,总是尝试用而不是用使MySQL充斥大量查询。
相反,你可以推测一个非常快速和非常优化的SQL查询,选择所有的坐标在一个简单的正方形$radius
内,而不是突然选择一个具有该半径的完美圆。然后,PHP
或其他什么可以快速过滤剩余的。
让我展示一下PHP中的概念:
// your input variables
$lat = 45.6072;
$lon = 7.65678;
$radius = 50; // expressed in Km
// every latitude degree° is ~ 111Km
$angle_radius_lat = $radius / 111;
// longitude takes into account equator distance
$angle_radius_lon = $angle_radius_lat * cos( deg2rad( $lat ) );
// define a simple square with your lat/lng as center
$min_lat = $lat - $angle_radius_lat;
$max_lat = $lat + $angle_radius_lat;
$min_lon = $lon - $angle_radius_lon;
$max_lon = $lon + $angle_radius_lon;
// query places inside the square
// use here your own database function
$results_raw = query_results( "SELECT latitude, longitude FROM ... WHERE latitude BETWEEN $min_lat AND $max_lat AND longitude BETWEEN $min_lon AND $max_lon" );
// filter the surplus outside the circle
$results = [];
foreach( $results_raw as $result ) {
if( getDistanceBetweenPointsNew( $lat, $lon, $result->latitude, $result->longitude, 'Km' ) <= $radius ) {
$results[] = $result;
}
}
// these are your places inside the circle of your radius
var_dump( $results );
通过这种方式,MySQL运行一个非常友好的查询,不会导致全表扫描,而PHP则使用类似于本页中发布的getDistanceBetweenPointsNew()
函数来剔除多余的内容,比较从结果集坐标到半径中心的距离。
重要的:为了不浪费巨大的性能增益,在坐标列(latitude
和longitude
)上创建一个数据库索引。黑客快乐!
我已经做了类似的销售房屋的应用程序,从给定点的距离排序,把它放在你的SQL选择语句:
((ACOS(SIN(' . **$search_location['lat']** . ' * PI() / 180) * SIN(**map_lat** * PI() / 180) + COS(' . **$search_location['lat']** . ' * PI() / 180) * COS(**map_lat** * PI() / 180) * COS((' . **$search_location['lng']** . ' - **map_lng**) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS "distance"
用相关的lat/lng值替换$search_location
, map_lat/map_lng值是包含lat/lng值的SQL列。然后,您可以按距离对结果排序,并使用where或having子句在50km范围内过滤我们的属性。
如果您需要分页等附加功能,我建议使用SQL作为与PHP相比的方法。
有点晚,但它可能会帮助某人-如果你想要最近的城市的位置,我不会去距离,因为这样一个孤立的位置不会检索任何东西。试试这个:
$G_how_close_to_find_cities = "1.1"; // e.g. 1.1 = 10% , 1.2=20% etc
$G_how_many_cities_to_find_by_coordinates = "10";
$query = "SELECT * from Cities WHERE
Cities__Latitude <= ('".$latitude*$G_how_close_to_find_cities."') AND Cities__Latitude >= ('".$latitude/$G_how_close_to_find_cities."')
AND Cities__Longitude <= ('".$longitude*$G_how_close_to_find_cities."') AND Cities__Longitude >= ('".$longitude/$G_how_close_to_find_cities."')
ORDER BY SQRT(POWER((Cities__Latitude - ".$latitude."),2)+POWER((Cities__Longitude - ".$longitude."),2)) LIMIT 0,".$G_how_many_cities_to_find_by_coordinates;