web-dev-qa-db-ja.com

PostgreSQL緯度経度クエリ

postgreSQLデータベースのlatitudeテーブルにlongitude列とlocation列があり、PostgreSQL関数で距離クエリを実行しようとしています。

マニュアルのこの章を読みました:

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

でも私はそこに何かが足りないと思います。

どうすればいいですか?利用可能な他の例はありますか

25
Idan

このモジュールはオプションであり、デフォルトの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;
22
strkol

次に、ポイント演算子を使用した別の例を示します。

初期設定(1回だけ実行する必要があります):

create extension cube;
create extension earthdistance;

そしてクエリ:

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

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

pointsLONGITUDE FIRSTで作成されることに注意してください。 ドキュメント

経度はx軸、緯度はy軸の直感的な考え方に近いため、ポイントは(経度、緯度)として解釈され、その逆は解釈されません。

それはひどいデザインです...しかし、それはそうです。

あなたの出力はマイルになります。

地球表面の2点間の距離を法定マイル単位で示します。

40
Steve Tauber

Earthdistanceモジュールを正しくインストールしたとすると、2つの都市間の距離がマイル単位で表示されます。この方法では、より単純な点ベースの地球距離を使用します。 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

Haversine式 を使用した、@ strkolの回答のより正確なバージョン

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など)で、出力はメートル単位です。

7
Thijs