【问题标题】:For each row, find if any previous rows contains a higher value对于每一行,查找任何先前的行是否包含更高的值
【发布时间】:2016-03-18 19:38:48
【问题描述】:

我正在尝试使用 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 &gt; any( 也总是相同的点。 我很难弄清楚 PostgreSQL 递归 CTE,所以如果有人可以帮助我,我将不胜感激。

【问题讨论】:

  • 注意:Postgres 递归查询需要RECURSIVE 关键字。
  • 好的,我会编辑我的问题

标签: sql postgresql postgis


【解决方案1】:

这听起来好像可以用窗口函数来解决。

这将为您提供一个真/假标志,用于记录先前的度数字段(按 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

根据您的问题,我不清楚您要应用此逻辑的每个几何点是否有一组 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

【讨论】:

  • 谢谢!没有仔细观察窗口功能。我想我必须学习这个主题。没有尝试按 geom 进行分区,因为它们中的每一个都只代表点,所以我猜没有任何 id 集
  • 很高兴它有帮助!窗口函数可以非常强大,绝对值得学习。我主要提到了 partition by 子句,以表明窗口不必应用于整个表 - 它可以基于列的当前值与子集相关:)
【解决方案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;

【讨论】:

  • 也是一个很好的答案。真的很抱歉,我不能接受两者都解决了我的问题
  • 同意...这是一个很好的答案。也很高兴看到非窗口函数方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多