提问人:deceze 提问时间:9/18/2008 最后编辑:Drewdeceze 更新时间:5/18/2021 访问量:6598
用于计算坐标邻近度的 SQL 查询
SQL query to calculate coordinate proximity
问:
我正在使用此公式来计算我的 (My)SQL 数据库中具有十进制格式的纬度和经度字段的条目之间的距离:
6371 * ACOS(SIN(RADIANS( %lat1% )) * SIN(RADIANS( %lat2% )) +
COS(RADIANS( %lat1% )) * COS(RADIANS( %lat2% )) * COS(RADIANS( %lon2% ) -
RADIANS( %lon1% )))
适当地替换 %lat1% 和 %lat2% 它可以在 WHERE 子句中用于查找另一个条目的特定半径内的条目,在 ORDER BY 子句中将其与 LIMIT 一起使用将找到最近的 x 个条目等。
我写这篇文章主要是作为我自己的笔记,但改进总是受欢迎的。:)
注意:正如 Valerion 在下面提到的,这是以公里为单位计算的。将 6371 替换为适当的替代数字,以使用米、英里等。
答:
2赞
Adam Hopkinson
9/18/2008
#1
我认为这是 Haversine 公式是对的吗?
评论
0赞
deceze
9/18/2008
我发现它是“大圆距离公式”,但看着它,是的,它很可能是。
1赞
Valerion
9/18/2008
#2
我在车辆跟踪应用程序上使用完全相同的方法,并且已经使用了多年。它工作得很好。快速检查一些旧代码表明,我将结果乘以6378137,如果内存可用,则转换为米,但我已经很久没有碰过它了。
我相信 SQL 2008 有一种新的空间数据类型,我想它允许在不知道这个公式的情况下进行这些类型的比较,并且还允许空间索引,这可能很有趣,但我还没有研究过它。
7赞
David
9/24/2008
#3
对于不支持三角函数的数据库(如 SQLite),可以使用勾股定理。
即使您的数据库支持三角函数,这也是一种更快的方法,但需要注意以下几点:
- 您需要将坐标存储在 x,y 网格中,而不是(或以及)lat,lng;
- 计算假设“平坦的地球”,但这对于相对本地的搜索来说很好。
这是我正在做的一个 Rails 项目的例子(中间重要的一点是 SQL):
class User < ActiveRecord::Base
...
# has integer x & y coordinates
...
# Returns array of {:user => <User>, :distance => <distance>}, sorted by distance (in metres).
# Distance is rounded to nearest integer.
# point is a Geo::LatLng.
# radius is in metres.
# limit specifies the maximum number of records to return (default 100).
def self.find_within_radius(point, radius, limit = 100)
sql = <<-SQL
select id, lat, lng, (#{point.x} - x) * (#{point.x} - x) + (#{point.y} - y) * (#{point.y} - y) d
from users where #{(radius ** 2)} >= d
order by d limit #{limit}
SQL
users = User.find_by_sql(sql)
users.each {|user| user.d = Math.sqrt(user.d.to_f).round}
return users
end
评论
0赞
Panagiotis Korros
10/20/2008
有没有办法将经度和纬度转换为 x、y 坐标?
1赞
2pha
7/24/2012
#4
我一直在使用它,忘记我从哪里得到它。
SELECT n, SQRT(POW((69.1 * (n.field_geofield_lat - :lat)) , 2 ) + POW((53 * (n.field_geofield_lon - :lon)), 2)) AS distance FROM field_revision_field_geofield n ORDER BY distance ASC
评论