2012-04-05 3 views
16

я есть latitude и longitude столбцов в таблице location в базе данных PostgreSQL, , и я пытаюсь выполнить запрос расстояния с помощью функции PostgreSQL.PostgreSQL широта запроса долгота

Я прочитал эту главу руководства:

https://www.postgresql.org/docs/current/static/earthdistance.html

, но я думаю, что не хватает чего-то там.

Как мне это сделать? Доступно больше примеров

ответ

20

Этот модуль является дополнительным и не установлен в стандартном instalatlion PostgreSQL. Вы должны установить его из каталога 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

+1

Я бы предположил, что они являются константами, используемыми для преобразования широты и долготы в мили. –

+4

Чтобы использовать KM вместо миль, используйте константы 111.12 и 92.215 для замены 69.1 и 57.3 –

5

Предполагая, что вы установили модуль earthdistance правильно, это даст вам расстояние в милях между двумя городами , Этот метод использует более простые наземные расстояния на основе точек. Обратите внимание, что аргументы точки() - это первая долгота, затем широта.

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; СОЗДАТЬ РАСШИРЕНИЕ СОСТОЯНИЯ, 'устанавливать заземление. – sudo

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 созданы с долготу в. Согласно documentation:

Точки берутся (долгота, широта), а не наоборот, потому что долгота ближе к интуитивной идее оси х и широты оси у.

Какой ужасный дизайн ... но так оно и есть.

+0

Получил голос за то, что он чище, чем другой ответ на основе 'earthdistance' – igorsantos07

+0

спасибо, большое решение! – Bagdat

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) и выход в метрах.

Смежные вопросы