5

给定一个包含 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:)

但是根据经纬度坐标和每个圆的半径,我们应该有:

  1. 圈 3(因为接近1.79 <- 12 - 10.21:)
  2. 圈1(因为接近6.42 <- 9.42 - 3:)
  3. 圈4(因为接近26.86 <- 30.86 - 4:)

有没有一种简单的方法可以在 SQL 中做到这一点?

4

4 回答 4

1

postgresql 的 contrib 中提供的cubeandearthdistance扩展可以处理这个问题,以产生至少近似的答案。具体来说,他们假设地球是一个简单的球体,这使得数学变得容易得多。

通过这些扩展,您可以生成第 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)快速扫描。

于 2012-07-10T20:38:37.217 回答
0

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

于 2012-07-10T07:39:18.540 回答
0

我建议你以下几点:

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

例如:

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

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

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

存储过程 的介绍你也需要光标来做这个

于 2012-07-10T09:56:13.030 回答