我只是在寻找有关最佳方法的建议......
我需要创建一个搜索功能,搜索邮政编码半径50英里范围内的“用户”。我有一个邮政编码表,其中包含所有美国邮政编码及其纬度/经度,但我只是想找出构建和查询数据的最佳方法......
我应该将纬度/经度列添加到users表并查询给定邮政编码半径范围内的所有用户吗?或者我应该在邮政编码表中查询半径范围内的所有邮政编码,然后查询具有结果的所有用户的用户表(邮政编码)?要么... ???我对此提出任何建议持开放态度!
谢谢!
答案 0 :(得分:19)
这是我找到的最佳方式。当然,这需要您在数据库中对所有的zip /编码进行lat / lon编码。
// get all the zipcodes within the specified radius - default 20
function zipcodeRadius($lat, $lon, $radius)
{
$radius = $radius ? $radius : 20;
$sql = 'SELECT distinct(ZipCode) FROM zipcode WHERE (3958*3.1415926*sqrt((Latitude-'.$lat.')*(Latitude-'.$lat.') + cos(Latitude/57.29578)*cos('.$lat.'/57.29578)*(Longitude-'.$lon.')*(Longitude-'.$lon.'))/180) <= '.$radius.';';
$result = $this->db->query($sql);
// get each result
$zipcodeList = array();
while($row = $this->db->fetch_array($result))
{
array_push($zipcodeList, $row['ZipCode']);
}
return $zipcodeList;
}
你应该能够放弃这个功能。将它传递给你想要半径的邮政编码的$ lat和$ lon,包括可选的半径,然后获取一个zipcodes列表。
你可以非常轻松地修改它以使所有用户获得zipcode IN(radius_sql)并让你的列表用户回来。
快乐的编码!
答案 1 :(得分:3)
http://www.micahcarrick.com/04-19-2005/php-zip-code-range-and-distance-calculation.html
我发现这非常棒。
“在邮政编码表中查询半径范围内的所有邮政编码,然后查询具有结果的所有用户的用户表格(邮政编码)”
我发现这是最好的方法,除非您需要将用户放在谷歌地图上。如果您只是列出里程范围内的用户,那么查询数据库(使用该类)以获取拉链列表应该非常容易,然后选择这些邮政编码中的所有用户。
Select * from Users where zip_code IN (19125,19081,19107.........);
应该这样做。
答案 2 :(得分:2)
答案 3 :(得分:2)
从这里开始,但请注意解决方案不是很快:
PHP Zip Code Range and Distance Calculation
现在要快速 - 我们将替换查找以使用空间索引:)
使用MySQL
在名为location的数据库中添加一列,并将其命名为POINT
确保它现在接受空值
运行以下SQL查询
UPDATE zip_code SET location = PointFromText(CONCAT('POINT(',lon,' ',lat,')'));
现在,让列不接受空值
将空间索引添加到位置列
在上述项目的代码中,使用以下内容替换函数'get_zips_in_range':
function get_zips_in_range($zip, $range, $sort=1, $include_base)
{
// returns an array of the zip codes within $range of $zip. Returns
// an array with keys as zip codes and values as the distance from
// the zipcode defined in $zip.
$this->chronometer(); // start the clock
$details = $this->get_zip_point($zip); // base zip details
if ($details == false) return false;
// This portion of the routine calculates the minimum and maximum lat and
// long within a given range. This portion of the code was written
// by Jeff Bearer (http://www.jeffbearer.com). This significanly decreases
// the time it takes to execute a query. My demo took 3.2 seconds in
// v1.0.0 and now executes in 0.4 seconds! Greate job Jeff!
// Find Max - Min Lat / Long for Radius and zero point and query
// only zips in that range.
$lat = $details[0];
$lon = $details[1];
$return = array(); // declared here for scope
$first = true;
$radius = $range/69.172;
$boundary = "POLYGON((";
for($i=0; $i <= 360; $i += 360/24)
{
if($first)
{
$first = false;
}
else
{
$boundary .= ', ';
}
$clon = $radius*cos(deg2rad($i)) + $lon;
$clat = $radius*sin(deg2rad($i)) + $lat;
$boundary .= "$clon $clat" ;
}
$boundary .= '))';
$sql = "SELECT zip_code, city, county, state_name, state_prefix, area_code, time_zone, lat, lon FROM zip_code WHERE MBRContains(GeomFromText('$boundary'), location);";
//echo $sql;
$r = mysql_query($sql);
if (!$r) { // sql error
$this->last_error = mysql_error();
return false;
} else {
while ($row = mysql_fetch_row($r)) {
// loop through the results to get the milage from src
$dist = $this->calculate_mileage($details[0],$row[7],$details[1],$row[8]);
if ($this->units == _UNIT_KILOMETERS) $dist = $dist * _M2KM_FACTOR;
$return[str_pad($row[0].', '.$row[1], 5, "0", STR_PAD_LEFT)] = round($dist, $this->decimals);
}
mysql_free_result($r);
}
// sort array
switch($sort)
{
case _ZIPS_SORT_BY_DISTANCE_ASC:
asort($return);
break;
case _ZIPS_SORT_BY_DISTANCE_DESC:
arsort($return);
break;
case _ZIPS_SORT_BY_ZIP_ASC:
ksort($return);
break;
case _ZIPS_SORT_BY_ZIP_DESC:
krsort($return);
break;
}
$this->last_time = $this->chronometer();
if (empty($return)) return false;
return $return;
}
答案 4 :(得分:1)
我会考虑首先减少具有边界的候选者的数量,然后担心第二步的半径。首先使用zipcode的坐标,然后在所有4个方向上计算50英里的长/纬度,然后使用简单的大于/小于标准选择该框中的候选者。如果你的用户群分布很好,这会大大减少你的候选集,那么你只需要做矢量距离数学来消除“角落”。
答案 5 :(得分:1)
我首先要搜索目标半径内的所有zipcodes。然后将所有返回的zipcodes与您的用户表zipcodes进行比较。拉出匹配的用户。
它找到半径的zipcodes,发现这个MySQL调用:
$query = 'SELECT zzip FROM ' . table .
' WHERE (POW((69.1*(zlongitude-"' .
$long . '")*cos(' . $long .
'/57.3)),"2")+POW((69.1*(zlatitude-"' .
$lat . '")),"2"))<(' . $radius .
'*' . $radius . ')';
MySQL为你做了所有的数学运算。
我在这里找到了一个使用它的类: http://www.nucleusdevelopment.com/code/do/zipcode
希望有所帮助。
答案 6 :(得分:0)
每个邮政编码的纬度/长度是该邮政编码的地理中心,对吗?因此,如果您首先找到地理中心在50英里范围内的邮政编码,那么使用这些邮政编码的用户,您可以轻松地返回50英里以外的用户。因此,你会牺牲一些准确性。
但是如果你有很多用户(超过邮政编码的数量),这会更快,因为你先查询较小的邮政编码表。您可以在users表中索引邮政编码,因此查找具有特定邮政编码的用户会很快。
只是一些想法!所以,如果你期待很多用户并且50英里的半径不需要精确,我会在50英里内找到邮政编码,然后是那些邮政编码内的用户。