一尘不染

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

sql

因此,我具有此功能,可以根据纬度,经度和半径参数来计算最近的城市。

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,这显然不是很有效。

任何帮助深表感谢。谢谢。


阅读 134

收藏
2021-03-17

共1个答案

一尘不染

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

在您的纬度表上放置一个索引。

根据问题中显示的Haversine公式,使自己成为haversine(lat1,lat2,long1,long2,unit)存储的函数。见下文

然后,根据已知的纬度,经度和公里数,执行此操作。

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将在纬度索引上使用索引范围扫描,以快速挑选出城市表中值得考虑的行。然后它将运行您的Haversine函数,该函数具有所有正弦和余弦数学,仅在这些行上。

我建议使用纬度,因为经度在地面上的距离会随纬度而变化。

请注意,这是粗略的。这对于找店员很好,但是如果您是土木工程师,则不要使用它-地球呈椭圆形,并且假设它是圆形的。

(对不起,111.12幻数。这是纬度中的公里数,即60海里。)


2021-03-17