按接近度排序结果(坐标和半径)

时间:2012-07-09 21:34:59

标签: mysql sql postgresql geolocation neo4j

给定一个包含4个圆圈的数据库,其中每个圆圈都有一个半径和一个地理位置中心:

id | radius | latitude | longitude
---+--------+----------+----------
 1 |      3 |    40.71 |    100.23
 2 |     10 |    50.13 |    100.23
 3 |     12 |    39.92 |    100.23
 4 |      4 |    80.99 |    100.23

注意:每个圆圈的经度都是相同的,以保持简单。

假设我们在圈子2上,我想根据latitude / longitude坐标和每个圈子的radius找到附近的每个圆圈。

例如,根据纬度/经度坐标,我们有这个顺序:

  1. 圈1(由于距离:9.42 <- 50.13 - 40.71
  2. 圈3(因为接近:10.21 <- 50.13 - 39.92
  3. 圈4(由于距离:30.86 <- 80.99 - 50.13
  4. 但是根据纬度/经度坐标和每个圆的半径,我们应该有:

    1. 圈3(因为接近:1.79 <- 12 - 10.21
    2. 圈1(由于距离:6.42 <- 9.42 - 3
    3. 圈4(由于距离:26.86 <- 30.86 - 4
    4. 在SQL中有一种简单的方法吗?

4 个答案:

答案 0 :(得分:1)

postgresql的contrib中提供的cubeearthdistance扩展可以处理这样做,以产生至少近似的答案。具体来说,他们认为地球是一个简单的球体,这使得数学变得更容易。

使用这些扩展程序,您可以生成圆圈2和其他圆圈之间的距离,如下所示:

select circle.id,
       earth_distance(ll_to_earth(circle.latitude, circle.longitude),
                      ll_to_earth(x.latitude, x.longitude))
 from circle,
      circle x
 where x.id = 2 and circle.id <> x.id
 order by 2;

校正圆半径应该只涉及从上方距离减去x.radiuscircle.radius,尽管您需要考虑半径所在的单位。默认情况下,earth_distance将以米为单位计算一个值。

现在,让查询执行除扫描整个圆圈列表以及计算每个圆圈的距离以外的其他内容,然后对它们进行排序和限制,这更具挑战性。有几种方法:

  • 使用立方体的能力使用gist索引,因此您可以创建索引以在任何圆圈的中心周围的某些框内进行搜索,从而减少要考虑的圆圈列表。
  • 在编辑圆圈时预先计算每个圆圈与所有其他圆圈之间的距离,使用触发器将此计算保存在单独的表格中。

第二个选项基本上以:

开头
create table circle_distance as
select a.id as a_id, b.id as b_id,
 earth_distance(ll_to_earth(a.latitude, a.longitude),
                ll_to_earth(b.latitude, b.longitude))
 from circle a, circle b
 where a.id <> b.id;
alter table circle_distance add unique(a_id, b_id);
create index on circle_distance(a_id, earth_distance);

然后一些相当繁琐的函数来删除/插入circle_distance中的相关行,由circle上的触发器调用。这意味着您可以:

select b_id from earth_distance where a_id = $circle_id order by earth_distance limit $n

此查询将能够使用(a_id,earth_distance)上的索引进行快速扫描。

答案 1 :(得分:0)

我建议查看PostGIS地理数据类型及其相关功能(例如:ST_Distance),而不是重新发明轮子

答案 2 :(得分:0)

我会告诉你以下内容:

创建1个表来计算相对于起始圆的相对距离

例如:

id | calc1  | calc2    
---+--------+----------
 1 |  9.42  |    1.97
 3 |  10.21 |    6.42
 4 |  30.86 |   62.86

Calc1是没有半径的计算 calc2是半径

的计算

然后创建一个存储过程,首先在运行时删除表,然后用正确的数据填充它,然后只读取目标表中的结果

Intrudoction to store procedures You will allso need cursor for this

答案 3 :(得分:0)