获取框中包含的最左侧|右侧|顶部|底部点

时间:2010-04-03 00:17:47

标签: php sql postgresql geometry

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

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

目前,我可以使用以下方式检索“单一屏幕”(在当前显示的地图所涵盖的区域内)的点:

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

现在我需要知道每个方向上的四个最远点,而不是我能够检索下四个“更偏远”的点。

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

1 个答案:

答案 0 :(得分:0)

您可以使用distance-to运算符(<->)与MIN聚合函数结合来查找最近距离,从而减少了查找行的其他列的问题{{ 3}}。操作员(<<>>|>><<|的严格左侧/右侧/上方/下方可用于将点数限制在方框的一侧。由于两个不同的点可能具有相同的距离,因此我们将结果minimal quantity设为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可以使用列上的索引(如果有的话)而不需要扫描表。由于距离是计算值,因此始终需要表扫描,并且查询将具有类似的性能。 limit可能会出于某种其他原因而不愿意使用语句,所以在选择方法之前应该这样做。