【问题标题】:Get most left|right|top|bottom point contained in box获取框内包含的最左|右|上|下点
【发布时间】:2010-04-03 00:17:47
【问题描述】:

我将兴趣点 (POI) 存储在 PostgreSQL 数据库中,并通过 PHP 脚本将它们检索到 Android 应用程序。为了减少互联网使用,我希望我的移动应用程序知道当前显示区域附近是否有任何点。

我的想法是存储包含已检索到的所有点的矩形的边界(换句话说:已检索到的最西部的左侧(西)最近点,已检索到的最北上方(北)的最近点等)当屏幕的任何边缘超出此范围时,我将进行下一个查询。

目前我可以使用以下方法检索“单屏”(当前显示的地图所覆盖的区域)中的点:

SELECT * FROM ch WHERE loc <@ (box '((".-$latSpan.", ".$lonSpan."),(".$latSpan.", ".-$lonSpan."))' + point '".$loc."')

现在我需要知道每个方向上四个最远的点,然后才能检索接下来的四个“更远”的点。

是否有可能直接从 PostgreSQL 获取这些点(或框)(可能使用一些“聚合点到框”功能)?

【问题讨论】:

  • 您确定框中的值的顺序吗?看起来您在 X(水平)坐标中存储纬度极值 (N/S),在 Y(垂直)坐标中存储经度。我希望这个盒子是box( (-longSpan, latSpan), (longSpan, -latSpan))

标签: php sql postgresql geometry


【解决方案1】:

您可以将距离运算符 (&lt;-&gt;) 与 MIN 聚合函数结合使用来查找最近的距离,从而减少查找具有某些 minimal quantity 的行的其他列的问题。严格的左/右/上/下运算符(&lt;&lt;&gt;&gt;|&gt;&gt;&lt;&lt;|)可用于将点限制在框的一侧。由于两个不同的点可能具有相同的距离,我们将limit 将结果保存到 1 行。假设屏幕方向,坐标向下和向右增加(而不是地图方向,增加北和东),我们得到:

-- Above, or North
SELECT * FROM ch WHERE loc <<| screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch
    WHERE loc <<| screen
) LIMIT 1

-- Right, or East
SELECT * FROM ch WHERE loc >> screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch 
    WHERE loc >> screen
) LIMIT 1

-- Below, or South
SELECT * FROM ch WHERE loc |>> screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch
    WHERE loc |>> screen
) LIMIT 1

-- Left, or West
SELECT * FROM ch WHERE loc << screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch 
    WHERE loc << screen
) LIMIT 1

注意,水平方向的最近点也可能是垂直方向的最近点;也就是说,以上四个语句的并集可能少于四行。

我们可以得到四个最近的点:

SELECT *, (loc <-> screen) AS distance FROM ch 
  WHERE NOT loc <@ screen
  ORDER BY distance
  LIMIT 4

但是,请注意,一些最近的点可能彼此位于同一方向。

我们可以得到最接近的点

SELECT *, (loc <-> screen) AS distance FROM ch 
  WHERE distance = (
      SELECT MIN(loc <-> screen) AS mindist FROM ch
  )
  LIMIT 1

SELECT *, (loc <-> screen) AS distance FROM ch 
  WHERE NOT loc <@ screen
  ORDER BY distance
  LIMIT 1

在计算列的最小值(或最大值)时,首选第一个,因为 DBMS 可以使用列上的索引(如果有)而无需扫描表。由于距离是计算值,因此始终需要进行表扫描,并且查询将具有相似的性能。 query analysis 可能会出现其他一些更喜欢声明的原因,因此您应该在选择方法之前这样做。

【讨论】:

  • 我需要一些时间来“编译”你的答案......但是,SELECT * FROM ch WHERE loc &lt;&lt;| screen AND (loc &lt;-&gt; screen) = ( SELECT MIN(loc &lt;-&gt; screen) AS mindist FROM ch WHERE loc &lt;&lt;| screen ) LIMIT 1 是否比SELECT * FROM ch WHERE loc &lt;&lt;| screen AND ORDER BY (loc &lt;-&gt; screen) ASC LIMIT 1 有任何优势?
  • @skyman:阅读我上一条评论。我怀疑你提到的两者中的后者会表现得更好,但可以肯定的是运行查询分析。
猜你喜欢
  • 1970-01-01
  • 2013-09-02
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
  • 2015-11-30
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多