【问题标题】:Geolocation distance SQL from a cities table [duplicate]来自城市表的地理位置距离 SQL [重复]
【发布时间】:2011-11-22 06:51:21
【问题描述】:

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

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

它会返回最近的城市。

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

目前,我只是调用该函数,然后将 ids 迭代到一个数组中,然后在 city 表中执行 WHEREIN,这显然不是很有效。

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

【问题讨论】:

  • 我会看看this other question。这应该会有所帮助。
  • 这将如何工作? :-)
  • lat、long 和 distance 将是传入的参数。它不准确,但应该是一个不错的估计。这需要有多准确?
  • 不“时间关键”准确。当用户点击“我所在区域的用户”时。他们可以选择一个收音机,它会过滤靠近他们的城市。注意:目前它相当准确。当然有些会在几公里之外,但这没什么大不了的。确实,越准确越好!但我也想要效率。
  • 公式需要包含城市表中位于一定纬度范围内的项目。

标签: mysql sql database geolocation


【解决方案1】:

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

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

根据您的问题中显示的半正弦公式,让自己成为一个半正弦(lat1,lat2,long1,long2,单位)存储函数。见下文

然后根据 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 幻数。这是一个纬度的公里数,即 60 海里。)


有关可行的距离函数,请参见此处。

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

【讨论】:

  • 嗨@Ollie Jones。感谢您的及时回复。老实说,我不太确定我是否完全理解如何更改我的函数以匹配你的 sql 所做的。谢谢! :-)
  • 我创建了半正弦公式,这是我的查询:SELECT * from cities_temp a where 52.205 &gt;= a.latitude - 100/111.12 and 52.205 &lt;= a.latitude + 100/111.12 and haversine(52.205,a.latitude, 0.144,a.longitude, 'KM') &lt;= 100 order by haversine(52.205,a.latitude, 0.144,a.longitude, 'KM') 其中纬度为 52.205,经度为 0.144(英国剑桥)
猜你喜欢
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多