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

Php 查询以查找给定lat/lng内的位置,php,mysql,sql,distance,latitude-longitude,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

所以我试图显示给定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";

那可不行。我猜这只是个逻辑问题,我在周日下午没办法想清楚,但我可能也做错了别的事情。非常感谢您的任何输入。

我认为您缺少一些括号,逻辑运算符有点混淆。这个怎么样

$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

如果你的应用程序在地理上不是大规模的,并且平均结果可以接受,我建议你使用这种方法。计算实际距离需要更长的时间,而且差异可能不会太大。这取决于您和应用程序的目标。

以下是我认为您需要的:。这将给你一个圆圈,以及你需要的排除能力

遵循帖子中描述的步骤,但不要

HAVING `distance`<= 10
这会给你范围内的东西


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

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

$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) 

你知道这个脚本只是在点周围做了一个盒子而不是一个圆吗?另外,$milesperdegree从数学上讲是一个纬度函数。这有一个很好的脚本——尽管是JavaScript——我没有意识到圆/方位。我猜经度变量应该是$lng+/-x英里,而不是$milesperdegree?因为地球不是一个完美的球体,度的长度不是固定的。如果您的脚本仅在一个小区域(如城市)上运行,则可以使用该区域的平均值。否则,需要更多的数学知识来提高精度。请参阅维基百科中的和。至于圆/方部分-简单应用毕达哥拉斯定理可以解决这个问题。顺便说一句,+1表示中间部分。。。而且,我不知道那个;快到了!但我必须承认我不太明白发生了什么,我想至少在数学上是这样。如果要查询出2到3英里之间的位置,该查询是什么?在这个应用程序中,3英里是我能走的最远的地方——只要大致在附近就足够了。虽然我很感激这些知识被丢弃以备将来使用。@nickfindley,它实际上只是一个毕达哥拉斯的a^2+b^2=c^2,在我们的例子中,n当然不会猜到。谢谢大家。非常感谢你们的来信。救了我很多!非常容易适应和清晰。
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)