2012-04-05 1387 views

回答

20

此模块是可选的,并未安装在默认的PostgreSQL instalatlion中。您必须从contrib目录安装它。

您可以使用下面的函数来计算坐标之间的大致距离(英里):

CREATE OR REPLACE FUNCTION distance(lat1 FLOAT, lon1 FLOAT, lat2 FLOAT, lon2 FLOAT) RETURNS FLOAT AS $$ 
DECLARE             
    x float = 69.1 * (lat2 - lat1);       
    y float = 69.1 * (lon2 - lon1) * cos(lat1/57.3);   
BEGIN              
    RETURN sqrt(x * x + y * y);        
END 
$$ LANGUAGE plpgsql; 
+2

你能解释一下这里的数学吗? 69.1和57.3代表什么? – jamesfzhang 2013-07-15 18:00:44

+1

我会想象它们是用来将纬度和经度转换为英里的常量。 – 2013-09-24 16:05:41

+4

要使用KM而不是英里数,请使用常量111.12和92.215来替换69.1和57.3 – 2014-06-09 23:19:30

5

假设你已经正确安装了earthdistance模块,这会给你两个城市之间的英里的距离。该方法使用更简单的基于点的地球距离。请注意,point()的参数是第一个经度,然后是纬度。

create table lat_lon (
    city varchar(50) primary key, 
    lat float8 not null, 
    lon float8 not null 
); 

insert into lat_lon values 
('London, GB', 51.67234320, 0.14787970), 
('New York, NY', 40.91524130, -73.7002720); 

select 
    (
    (select point(lon,lat) from lat_lon where city = 'London, GB') <@> 
    (select point(lon,lat) from lat_lon where city = 'New York, NY') 
) as distance_miles 

distance_miles 
-- 
3447.58672105301 
+0

中谢谢,此答案是执行此操作的最佳方法。你只需要运行'CREATE EXTENSION cube; CREATE EXTENSION earthdistance;'安装earthdistance。 – sudo 2015-07-27 23:51:15

21

下面是使用点操作又如:

create extension cube; 
create extension earthdistance; 
select (point(-0.1277,51.5073) <@> point(-74.006,40.7144)) as distance; 

    distance  
------------------ 
3461.10547602474 
(1 row) 

注意points经度FIRST创建。根据documentation

因为经度更接近直观的x轴和纬度到y轴,所以点取经度,纬度,反之亦然。

这是可怕的设计......但是就是这样。

+0

得到了一个清洁比基于'earthdistance'的其他答案投票 – igorsantos07 2015-11-22 05:24:49

+0

谢谢你,伟大的解决方案! – Bagdat 2016-06-18 19:50:58

3

@ strkol的回答的一个更精确的版本,使用Haversine formula

CREATE OR REPLACE FUNCTION distance(
    lat1 double precision, 
    lon1 double precision, 
    lat2 double precision, 
    lon2 double precision) 
    RETURNS double precision AS 
$BODY$ 
DECLARE 
    R integer = 6371e3; -- Meters 
    rad double precision = 0.01745329252; 

    φ1 double precision = lat1 * rad; 
    φ2 double precision = lat2 * rad; 
    Δφ double precision = (lat2-lat1) * rad; 
    Δλ double precision = (lon2-lon1) * rad; 

    a double precision = sin(Δφ/2) * sin(Δφ/2) + cos(φ1) * cos(φ2) * sin(Δλ/2) * sin(Δλ/2); 
    c double precision = 2 * atan2(sqrt(a), sqrt(1-a));  
BEGIN              
    RETURN R * c;   
END 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 

输入是在度(例如52.34273489,6.23847)和输出是在米。