【问题标题】:PostgreSQL latitude longitude queryPostgreSQL经纬度查询
【发布时间】:2012-04-19 13:10:51
【问题描述】:

我在 PostgreSQL 数据库的 location 表中有 latitudelongitude 列, 我正在尝试使用 PostgreSQL 函数执行距离查询。

我阅读了手册的这一章:

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

但我认为我在那里遗漏了一些东西。

我该怎么做?是否有更多可用示例

【问题讨论】:

    标签: postgresql postgis


    【解决方案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)
    

    请注意,points 是使用 LONGITUDE FIRST 创建的。根据documentation

    点被视为(经度,纬度),反之则不然,因为经度更接近 x 轴的直观概念,纬度更接近 y 轴。

    这是一个糟糕的设计......但就是这样。

    您的输出将以 英里 为单位。

    给出地球表面两点之间的法定英里距离。

    【讨论】:

    • 投票赞成比基于earthdistance的其他答案更干净
    • “给出地球表面两点之间的法定英里距离。”
    • 是否每次都必须运行“创建扩展”查询?
    • @TheRealChx101 我已经更新了说明,明确说明这些是用于设置的,您只需要运行一次
    • 这不起作用。 cubeearthdistance 均由 pg_available_extensions 安装和验证。重新启动 PostgreSQL。 [42883] ERROR: operator does not exist: point &lt;@&gt; point。与 stackoverflow.com/questions/2665786/… 相同可能是 Windows 上的 Postgres 的问题?
    【解决方案2】:

    此模块是可选的,未安装在默认的 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;
    

    【讨论】:

    • 你能解释一下这里的数学吗? 69.1 和 57.3 代表什么?
    • 我想它们是用于将纬度和经度转换为英里的常量。
    • 要使用 KM 而不是英里,请使用常量 111.12 和 92.215 替换 69.1 和 57.3
    • 为什么使用 Postgresql 而不是使用 Java 的方法,例如在函数中
    • @FernandoPie 当有很多行并且距离是WHERE 子句的一部分时,让数据库过滤结果比先将所有行传输到Java 更快。
    【解决方案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),输出以米为单位。

    【讨论】:

    • 我要这个答案。
    • 我不确定我是否同意使用 Δλ 等特殊字符是个好主意。
    【解决方案4】:

    假设您已正确安装 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
    

    【讨论】:

    • 谢谢,这个答案是最好的方法。你只需要运行CREATE EXTENSION cube; CREATE EXTENSION earthdistance; 来安装earthdistance。
    【解决方案5】:

    另一种 Haversine 公式,返回里程。 (source)

    CREATE OR REPLACE FUNCTION public.geodistance(
        latitude1 double precision,
        longitude1 double precision,
        latitude2 double precision,
        longitude2 double precision)
      RETURNS double precision AS
    $BODY$
    SELECT asin(
      sqrt(
        sin(radians($3-$1)/2)^2 +
        sin(radians($4-$2)/2)^2 *
        cos(radians($1)) *
        cos(radians($3))
      )
    ) * 7926.3352 AS distance;
    $BODY$
      LANGUAGE sql IMMUTABLE
      COST 100;
    

    【讨论】:

      猜你喜欢
      • 2013-12-29
      • 1970-01-01
      • 2013-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-29
      • 1970-01-01
      相关资源
      最近更新 更多