【问题标题】:Calculate the geographic distance between 2 duplicated cases计算2个重复案例之间的地理距离
【发布时间】: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 功能),要么查看stackoverflow.com/a/59171192/3027266
  • 如果您对降低的准确性感到满意,您甚至可以使用简单的毕达哥拉斯:111km ⋅ sqrt((Δlat² + cos(lat) ⋅ Δlon²))。这些是真正的价值吗? 0.1° 大约是 11 公里(在赤道处),因此任何大于 0.01 的原始差异肯定超过 100 米。

标签: sql oracle gis distance


【解决方案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 ( house{2} )
  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 ( house{2} )
  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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    相关资源
    最近更新 更多