查询以查找给定lat / lng内的位置

时间:2011-02-27 19:53:21

标签: php mysql sql distance latitude-longitude

所以我试图显示给定lat / lng范围内的地点列表。我对此没有任何问题:

一英里内的地方 (地方名单......)

使用类似

的内容
SELECT * FROM places WHERE lat < $latmax AND lat > $latmin AND lng < $lngmax AND lng > $lngmin

但后来我想列出两英里内的地方,但不是在一英里内 - 也就是说,我不想重复第一次查询的结果。

以下是我尝试过的一个版本:

$milesperdegree = 0.868976242 / 60.0 * 1.2;

// 1 mile -- this works
$degrees = $milesperdegree * 1;
$latmin = $lat - $degrees;
$latmax = $lat + $degrees;
$lngmin = $lng - $degrees;
$lngmax = $lng + $degrees;

$query = "SELECT * FROM places WHERE lat < $latmax AND lat > $latmin AND lng < $lngmax AND lng > $lngmin";

// 2 miles -- this doesn't work
$degrees_2 = $milesperdegree * 2;
$latmin_2 = $lat - $degrees_2;
$latmax_2 = $lat + $degrees_2;
$lngmin_2 = $lat - $degrees_2;
$lngmax_2 = $lat + $degrees_2;

$query = "SELECT * FROM places WHERE ";
$query .= "lat BETWEEN $latmax AND $latmax_2 AND lng BETWEEN $lngmax AND $lngmax_2 OR ";
$query .= "lat BETWEEN $latmin AND $latmin_2 AND lng BETWEEN $lngmin AND $lngmin_2 OR ";
$query .= "lat BETWEEN $latmax AND $latmax_2 AND lng BETWEEN $lngmin AND $lngmin_2 OR ";
$query .= "lat BETWEEN $latmin AND $latmin_2 AND lng BETWEEN $lngmax AND $lngmax_2";

那不是这样做的。我猜这只是一些逻辑我周日下午无法解决,但我也可能做错了。任何意见都非常感谢。

3 个答案:

答案 0 :(得分:4)

我们或多或少地像下面的代码那样实现它(免责声明:我从文件中删除了这个并删除了与手头问题无关的代码。我没有运行它,但你应该能够得到这个想法。

$maxLat = $city->latitude + ($max_distance / 69); // 69 Miles/Degree
$minLat = $city->latitude - ($max_distance / 69);

$maxLon = $city->longitude + ($max_distance / (69.172 * cos($city->latitude * 0.0174533)));
$minLon = $city->longitude - ($max_distance / (69.172 * cos($city->latitude * 0.0174533)));

// Simplify terms to speed query
$originLatRadCos = cos($city->latitude * 0.0174533);
$originLatRadSin = sin($city->latitude * 0.0174533);
$originLonRad = $city->longitude * 0.0174533;

$city_distance_query = "
SELECT city_id, 
  3963 * acos(($originLatRadSin * sin( latitude * 0.0174533)) + 
  ($originLatRadCos * cos(latitude * 0.0174533) * cos((longitude * 0.0174533) -
  $originLonRad))) AS distanceFromOrigin
FROM cities
WHERE
 latitude < $maxLat AND latitude > $minLat AND longitude < $maxLon AND longitude > $minLon";

查询的其余部分

SELECT cities.city_name, CityDistance.distanceFromOrigin,
FROM cities 
INNER JOIN ($city_distance_query) AS CityDistance ON CityDistance.city_id=cities.city_id
WHERE (distanceFromOrigin < $distance OR distanceFromOrigin IS NULL) 

答案 1 :(得分:2)

我认为你缺少一些括号,并且逻辑运算符有点混乱。怎么样。

$query  = "SELECT * FROM places WHERE ";
$query .= "((lat BETWEEN $latmin_2 AND $latmax_2) AND NOT (lat BETWEEN $latmin AND $latmax)) AND ";
$query .= "((lng BETWEEN $lngmin_2 AND $lngmax_2) AND NOT (lng BETWEEN $lngmin AND $lngmax)) AND ";

修改

解决圆/方问题:

$query  = "SELECT * FROM places WHERE ";
$query .= "(POW((lat - $lat) * $avgMilesPerLatDeg,2) + ".
           "POW((lng - $lng) * $avgMilesPerLngDeg,2) BETWEEN 1 AND 4)";
// the four at the end is 2 squared

如果您的应用不是大规模(地理位置)并且平均值产生可接受的结果,我建议使用此方法。计算实际距离需要更长的时间来计算,差异可能不会那么大。这取决于您和您的应用程序的目标。

答案 2 :(得分:0)

以下是我认为您需要的内容:Calculate distance in MySQL using lat/lng。这将为您提供一个圆圈,并具有您需要排除的能力。

按照帖子中描述的步骤,而不是

HAVING `distance`<= 10

您需要输入

HAVING `distance` BETWEEN 1 AND 2

这将为您提供范围内的东西。

PS:如果你有一个包含大量记录的数据库 - 你需要对它的执行情况进行基准测试,然后进行一些优化(如果性能不可接受的话)