好吧已经有一段时间了,因为iv不得不做一些复杂的事情而且我有点难过。
我有一个库类,它接收一个邮政编码,并在输入的邮政编码的半径内返回一个关联的邮政编码数组,邮政编码为关键,并与原始邮政编码的距离为值。
示例:FK27DJ => 0.094146570284875
网络应用程序是一个外卖餐厅查找器,我需要运行一个查询,找到每种类型最接近的信息到输入的邮政编码。
基于takeaway_type_id字段有4种类型的外卖。因此,如果用户输入他们自己的邮政编码,将向他们展示每种类型的单个外卖,这也是该类型与输入的邮政编码最接近的外卖。
所以我需要从库类中传入一个postcodes数组,并在takeaways表中搜索每种类型最近的外卖。
这有意义吗?
外卖表包含以下相关字段:
id(int),takeaway_type_id(int),邮政编码
这可以在一个查询中完成吗?该网站是基于PHP的。
答案 0 :(得分:0)
是。由于这看起来像英国邮政编码,您需要另一个表格,将邮政编码映射到GPS坐标(经度和纬度)。你可以从这里得到它。 http://jamiethompson.co.uk/web/2008/07/24/full-uk-postcode-database-for-free/(其他地方也可能有,请查看http://www.freepostcodes.org.uk/)
然后你需要在SQL中进行“选择”,加入两个表,计算你可以在SQL中做的距离。 “SQRT(POWER(Long1 - long2,2)+ POWER(Lat1 - Lat2,2))”将为您提供近似距离。警告:由于需要为每行计算,请将可能的结果限制为Long + -range,Lat + -range。
要获得准确的距离,您需要一点触发。这是我在最近的类似应用程序中使用的函数,您应该能够按摩它来工作甚至构建SQL查询。
function CalculateDistance($Longitude1, $Latitude1, $Longitude2, $Latitude2) {
// Not perfect for curvature of earth on the diaganol, but it's close enough ;)
$LatDiff = abs($Latitude1 - $Latitude2);
$LongDiff = abs($Longitude1 - $Longitude2);
// Convert to meters - 1 deg latitude = 111.12km
$mLatDiff = $LatDiff * 0.11112;
$mLongDiff = $LongDiff * 0.11112 * cos(($Latitude1 + $Latitude2) / 2);
// Work out difference.
$Diff = sqrt( ($mLatDiff * $mLatDiff) + ($mLongDiff * $mLongDiff) );
return $Diff;
}
编辑:添加代码示例
未经测试的代码,但是来自最近的一个项目。需要语法检查和调整,但会提出想法。
$UserPostcode = "AB1 2FG";
// Find the Long/Lat of the user (you don;t have to do this, but it saves a lot of DB stress)
// Postcodes is the table that links users to postcodes
$sql = 'SELECT long, lat FROM postcodes WHERE postcode="' . mysql_real_escape_string($UserPostcode) .'"';
// ... Missing a few lines of check row exists, error reporting etc
$UserLat = $row['lat'];
$UserLong = $row['long'];
// Next, come up with an acceptable range so as not to over-stress the DB:
// What are the acceptable limits?
// 1 deg latitude = 111.12km
// LATITUDE: 1km = 1/111.2 degrees of latitude = 0.0089992800575953923686105111591073
// LONGITUDE: 1km = 1/(111.2 * cos(LATITUDE))
$RangeLat = 8 * 1/111.2; // For 8km = 5 miles. Work out what you want here, the larger = more DB stress
$RangeLong = 8 * 1/(111.2 * cos(deg2rad($UserLat)); // For 8km = 5 miles. Work out what you want here, the larger = more DB stress
// Now the query you want.
// You'll need to change this to get restauants by group, but this gives you the essence of what you need:
$sql = 'SELECT r.restaurant_id, r.OtherDetails, r.postcode,
p.lat, p.long,
SQRT(POWER(p.lat-'.$UserLat.',2) + POWER(p.long-'.$UserLong.',2)) AS distance
FROM resturants r
LEFT JOIN postcodes p ON r.postcode=p.postcode
WHERE p.lat >='.($UserLat - $RangeLat).' AND p.lat <='.($UserLat + $RangeLat).' AND p.long>='.($UserLong-$RangeLong).' AND p.long>='.($UserLong+$RangeLong).'
ORDER BY SQRT(POWER(p.lat-'.$UserLat.',2) + POWER(p.long-'.$UserLong.',2)) ASC';
if (!$result = mysql_query($sql)) { ExitError(4, $sql . '<br />' . mysql_error()); }
while ($row = mysql_fetch_assoc($result)) {
// This is where you can count the 4 in each category, and disregard if you get more that 4.
// If you get less than 4, offer to expand the range - or stick in a loop and do it automatically.
// Also for efficienty, I'd suggest you remove the "distance" calculation from the SQL and use the function above
// The function above it more accurate as it users cosine. Then simply sort by distance here instead on in SQL.
// Also note the above function is written for the northern hemisphere. Also won't work across the date line ;)
// But that shouldn't be a worry.
}
mysql_free_result($result);
但是 - 可以在一个查询中完成:当然,如果你想关闭SQL服务器
同样,没有经过测试,但会给你一个如何做的要点。不过我强烈建议不要这样做!
$sql = 'SELECT r.restaurant_id, r.OtherDetails, r.postcode,
p.lat, p.long,
SQRT(POWER(p.lat-p2.lat,2) + POWER(p.long-p2.long,2)) AS distance
FROM resturants r
LEFT JOIN postcodes p ON r.postcode=p.postcode
LEFT JOIN postcodes p2 ON p2.postcode="' . mysql_real_escape_string($UserPostcode) .'"
ORDER BY SQRT(POWER(p.lat-p2.lat,2) + POWER(p.long-p2.long,2)) ASC';
//如果你走那条路,你想要超精准,我会让你弄清楚如何在那里获得COS :)。您需要的mySQL函数是RADIANS()和COS()