计算2个重复案例之间的地理距离

Posted

技术标签:

【中文标题】计算2个重复案例之间的地理距离【英文标题】:Calculate the geographic distance between 2 duplicated cases 【发布时间】:2021-11-20 13:40:31 【问题描述】:

我正在尝试计算数据库中 2 个重复案例之间的距离 我正在研究 SQL Oracle

例如:

ID ID_Household  long   lat
1  1             3.2    22.2
1  2             2.3    21.2
2  3             22.2   45.4
2  4             12.8   15.9
3  3             11.2   13.2
3  4             11.2   13.2

我希望输出为

ID  duplication_status    distance
1   2                     more than 100 meter
3   2                     less than 100 meter

我尝试阅读大量文章和问题,但无法构建逻辑 How to calculate distance between multiple points in SQL Server?

【问题讨论】:

提示:聚合查询包含 HAVING 子句以及 WHERE 子句中的 sdo_geom.sdo_distancesdo_geometrysdo_point_type 函数。 你能打个例子吗? 你可以check out 要么使用sdo_geom.sdo_distance(这是您必须付费购买的可选Oracle 功能),要么查看***.com/a/59171192/3027266 如果您对降低的准确性感到满意,您甚至可以使用简单的毕达哥拉斯:111km ⋅ sqrt((Δlat² + cos(lat) ⋅ Δlon²))。这些是真正的价值吗? 0.1° 大约是 11 公里(在赤道处),因此任何大于 0.01 的原始差异肯定超过 100 米。 【参考方案1】:

您可以create the function:

CREATE FUNCTION haversine_distance(
  lat1  IN NUMBER,
  long1 IN NUMBER,
  lat2  IN NUMBER,
  long2 IN NUMBER
) RETURN NUMBER DETERMINISTIC
IS
  PI           CONSTANT NUMBER := ASIN(1) * 2;
  R            CONSTANT NUMBER := 6371000; -- Approx. radius of the earth in m
  PHI1         CONSTANT NUMBER := lat1 * PI / 180;
  PHI2         CONSTANT NUMBER := lat2 * PI / 180;
  DELTA_PHI    CONSTANT NUMBER := (lat2 - lat1) * PI / 180;
  DELTA_LAMBDA CONSTANT NUMBER := (long2 - long1) * PI / 180;
  a NUMBER;
  c NUMBER;
BEGIN
  a := SIN(delta_phi/2) * SIN(delta_phi/2) + COS(phi1) * COS(phi2) *
          SIN(delta_lambda/2) * SIN(delta_lambda/2);
  c := 2 * ATAN2(SQRT(a), SQRT(1-a));
  RETURN R * c; -- in metres
END;
/

然后使用查询:

SELECT id,
       haversine_distance(lat1, long1, lat2, long2) AS distance_metres,
       CASE
       WHEN haversine_distance(lat1, long1, lat2, long2) > 100
       THEN 'more than 100 meter'
       ELSE 'less than 100 meter'
       END AS distance
FROM   table_name
MATCH_RECOGNIZE(
  PARTITION BY id
  ORDER     BY id_household
  MEASURES
    FIRST(longitude) AS long1,
    FIRST(latitude)  AS lat1,
    LAST(longitude)  AS long2,
    LAST(latitude)   AS lat2
  PATTERN ( house2 )
  DEFINE
    house AS 1 = 1
);

或任何其他将行分组成对并旋转然后调用函数的方法。

其中,对于样本数据:

CREATE TABLE table_name (ID, ID_Household, longitude, latitude) AS
SELECT 1, 1,  3.2, 22.2 FROM DUAL UNION ALL
SELECT 1, 2,  2.3, 21.2 FROM DUAL UNION ALL
SELECT 2, 3, 22.2, 45.4 FROM DUAL UNION ALL
SELECT 2, 4, 12.8, 15.9 FROM DUAL UNION ALL
SELECT 3, 3, 11.2, 13.2 FROM DUAL UNION ALL
SELECT 3, 4, 11.2, 13.2 FROM DUAL;

输出:

ID DISTANCE_METRES DISTANCE
1 144947.804966182829942744055657720422603 more than 100 meter
2 3395725.11733156831056822390960787854383 more than 100 meter
3 0 less than 100 meter

或者,如果您想使用 SDO 几何函数:

SELECT id,
       sdo_geom.sdo_distance(
         sdo_geometry(
           2001, -- 2D co-ordinate containing a single point 
           4326, -- Spatial reference system id (SRID) for WGS84 coordinates
           sdo_point_type(lat1,long1,null), 
           null, 
           null
         ),
         sdo_geometry(
           2001, -- 2D co-ordinate containing a single point 
           4326, -- Spatial reference system id (SRID) for WGS84 coordinates
           sdo_point_type(lat2,long2,null), 
           null, 
           null
         ),
         0.005,
         'unit=m'
       ) AS distance_metres,
       CASE
       WHEN sdo_geom.sdo_distance(
              sdo_geometry(
                2001, -- 2D co-ordinate containing a single point 
                4326, -- Spatial reference system id (SRID) for WGS84 coordinates
                sdo_point_type(lat1,long1,null), 
                null, 
                null
              ),
              sdo_geometry(
                2001, -- 2D co-ordinate containing a single point 
                4326, -- Spatial reference system id (SRID) for WGS84 coordinates
                sdo_point_type(lat2,long2,null), 
                null, 
                null
              ),
              0.005,
              'unit=m'
            ) > 100
       THEN 'more than 100 meter'
       ELSE 'less than 100 meter'
       END AS distance
FROM   table_name
MATCH_RECOGNIZE(
  PARTITION BY id
  ORDER     BY id_household
  MEASURES
    FIRST(longitude) AS long1,
    FIRST(latitude)  AS lat1,
    LAST(longitude)  AS long2,
    LAST(latitude)   AS lat2
  PATTERN ( house2 )
  DEFINE
    house AS 1 = 1
)

哪些输出:

ID DISTANCE_METRES DISTANCE
1 149223.001672844 more than 100 meter
2 3293714.72371264 more than 100 meter
3 0 less than 100 meter

db小提琴here

【讨论】:

以上是关于计算2个重复案例之间的地理距离的主要内容,如果未能解决你的问题,请参考以下文章

如何计算两个经纬度之间的距离[重复]

2个城市之间的经度和纬度距离等式是啥[重复]

地理位置:通过距离获取纬度和经度[重复]

计算两点之间距离的方法[重复]

2个小数点之间的距离[重复]

为数组 2 的每一行计算数组 1 的一行之间的距离,然后移动到数组 1 的下一行并重复