对于每一行,查找以前的任何行是否包含更高的值

时间:2016-03-18 10:48:10

标签: sql postgresql postgis

我正在尝试使用PostgreSQL和PostGIS中的SQL解决视线(LoS)问题。要做到这一点,我有一个表pitch_at_point,其中包含一个id,一个点几何和一个音高。

pitch_at_point(id integer,geom geometry,degrees float)

id列的最低值是LoS的起点,最高值是最远的。对于这些点中的每一点,我想确定是否存在具有较低id的点,其也具有较高的音高(度)。如果是这种情况,则无法看到这一点。

我一直在努力寻找解决方案。我已尝试使用递归查询,如下面的SQL:

WITH RECURSIVE 
walk_points AS 
(
  SELECT ARRAY[id] AS idlist,geom,degrees,id
  FROM pitch_at_point
  WHERE degrees = (SELECT max(degrees) FROM pitch_at_point)
  UNION ALL
  SELECT array_append(w.idlist, n.id) AS idlist,n.geom,n.degrees,n.id 
  FROM pitch_at_point n, walk_points w
  WHERE n.degrees < any(SELECT n.degrees FROM pitch_at_point WHERE NOT       
  w.idlist @> ARRAY[n.id])
)
SELECT * FROM walk_points

我希望得到所有点数之前返回的点数更高,但我只得到一个点的结果,即使我使用WHERE n.degrees > any(也总是相同的点。 我很难搞清楚PostgreSQL的递归CTE,所以如果有人能帮助我,我会很感激。

2 个答案:

答案 0 :(得分:2)

我可能错了,但这不是简单的:

select
  id, geom, degrees
from pitch_at_point
where exists
(
  select *
  from pitch_at_point before
  where before.id < pitch_at_point.id
  and before.degree > pitch_at_point.degree
);

这将获得ID较低的记录具有较高音高的所有点。

使用MAX的窗口版本可能会更快:

select id, geom, degrees
from
(
  select
    id, geom, degrees,
    max(degreees) over (order by id rows between unbounded preceding and 1 preceding) 
      as max_degrees_before
  from pitch_at_point
) data
where degrees < max_degrees_before;

答案 1 :(得分:2)

这听起来好像可以通过窗口功能解决。

这将为您提供前/后度数字段(按ID排序)大于当前行的度数的记录的真/假标志:

    case  when degrees < max( degrees ) over( 
            order by id 
            rows between unbounded preceding and 1 preceding 
          ) 
          then true 
          else false 
    end as higher_value_present

请在此处查看SQLfiddle:http://sqlfiddle.com/#!15/23196/1

根据您的问题,我不清楚您是否希望将此逻辑应用于每个geom点的一组ID?如果是这种情况,您可以通过geom:

对窗口功能进行分区
    case  when degrees < max( degrees ) over( 
            partition by geom
            order by id 
            rows between unbounded preceding and 1 preceding 
          ) 
          then true 
          else false 
    end as higher_value_present