来自城市表的地理位置距离SQL

时间:2011-09-21 20:04:10

标签: mysql sql database geolocation

所以我有这个函数来根据纬度,经度和半径参数计算最近的城市。

DELIMITER $$
DROP PROCEDURE IF EXISTS `world_db`.`geolocate_close_cities`$$
CREATE PROCEDURE `geolocate_close_cities`(IN p_latitude DECIMAL(8,2), p_longitude DECIMAL(8,2), IN p_radius INTEGER(5))
BEGIN
        SELECT id, country_id, longitude, latitude, city,
        truncate((degrees(acos( sin(radians(latitude)) 
        * sin(radians(p_latitude)) 
        + cos(radians(latitude)) 
        * cos(radians(p_latitude)) 
        * cos(radians(p_longitude - longitude) ) ) ) 
        * 69.09*1.6),1) as distance 
        FROM cities
        HAVING distance < p_radius
        ORDER BY distance desc;
    END$$

DELIMITER ;

这是我的城市表的结构:

> +------------+-------------+------+-----+---------+----------------+ |
> Field      | Type        | Null | Key | Default | Extra          |
> +------------+-------------+------+-----+---------+----------------+ |
> id         | int(11)     | NO   | PRI | NULL    | auto_increment | |
> country_id | smallint(6) | NO   |     | NULL    |                | |
> region_id  | smallint(6) | NO   |     | NULL    |                | |
> city       | varchar(45) | NO   |     | NULL    |                | |
> latitude   | float       | NO   |     | NULL    |                | |
> longitude  | float       | NO   |     | NULL    |                | |
> timezone   | varchar(10) | NO   |     | NULL    |                | |
> dma_id     | smallint(6) | YES  |     | NULL    |                | |
> code       | varchar(4)  | YES  |     | NULL    |                |
> +------------+-------------+------+-----+---------+----------------+

效果很好。

我要做的事(伪代码)是这样的:

SELECT * FROM cities WHERE DISTANCE(SELECT id FROM cities WHERE id={cityId}, {km)) 

它会让我回到最近的城市。

关于我如何做到这一点的任何想法?

目前,我只是调用函数,然后将id迭代到数组中,然后在city表中执行WHEREIN,这显然效率不高。

任何帮助都非常感谢。感谢。

2 个答案:

答案 0 :(得分:1)

如果您可以限制城市与当地位置之间的最大距离,请利用一分钟纬度(南北)为一海里的事实。

在纬度表上添加一个索引。

根据问题中显示的半身定式,让自己成为一个哈希(lat1,lat2,long1,long2,unit)存储函数。见下文

然后按照mylatitude,mylongitude和mykm做这个。

SELECT * 
  from cities a
 where :mylatitude >= a.latitude  - :mykm/111.12
   and :mylatitude <= a.latitude  + :mykm/111.12
   and haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM') <= :mykm
 order by haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM')

这将使用纬度边界框粗略地排除距离您的点太远的城市。您的DBMS将使用纬度指数上的索引范围扫描快速选出您的城市表中值得考虑的行。然后它将运行你的hasrsine函数,一个包含所有正弦和余弦数学的函数,仅在那些行上运行。

我建议纬度,因为经度的地面距离随纬度而变化。

注意这是粗糙的。对于商店发现者来说这很好,但是如果你是一名土木工程师则不要使用它 - 地球有一个椭圆形状,这就假设它是圆形的。

(抱歉111.12幻数。这是纬度的公里数,即六十海里。)


请参阅此处了解可行的距离函数。

Why does this MySQL stored function give different results than to doing the calculation in the query?

答案 1 :(得分:0)

我会看看this other question。这应该有所帮助。