postgresql SQL在起始标志之间选择行并在几何图形上生成线串

flmtquvp  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(2)|浏览(138)

我有一个问题,我相信你的Maven可以很容易地回答:-)
从postgresql/postgis中的一个表,内容如下
ID|车|时间戳|geom|起始旗标
903 |test1| 2019 - 03 - 11 08:38:52| 0101000020E61000001D33F55| 4
904 |test1| 2019 - 03 - 11 08:39:02| 0101000020E6100000A40117B| 0
905 |test1| 2019 - 03 - 11 08:39:13| 0101000020E6100000740179C| 0
906 |test1| 2019 - 03 - 11 08:39:23| 0101000020E6100000E68013C| 0
907 |test1| 2019 - 03 - 11 08:39:34| 0101000020E610000014B1886| 0
908 |test1| 2019 - 03 - 11 08:39:44| 0101000020E61000004309E9D| 4
909 |test1| 2019 - 03 - 11 08:39:54| 0101000020E61000004C6B781| 0
910 |test1| 2019 - 03 - 11 08:40:05| 0101000020E61000002DC6658| 0
911 |test1| 2019 - 03 - 11 08:40:15| 0101000020E6100000A0B591A| 0
912 |test1| 2019 - 03 - 11 08:40:26| 0101000020E61000000E1A55E| 0
913 |test1| 2019 - 03 - 11 08:40:36| 0101000020E6100000D7DF128| 0
914 |test1| 2019 - 03 - 11 08:40:46| 0101000020E61000001C1E673| 4
915 |test1| 2019 - 03 - 11 08:40:57| 0101000020E6100000DD24068| 0
916 |test1| 2019 - 03 - 11 08:41:07| 0101000020E6100000CBE48A4| 0
917 |test1| 2019 - 03 - 11 08:41:17| 0101000020E610000093FFC9D| 0
918 |test1| 2019 - 03 - 11 08:41:28| 0101000020E61000000B3A6B0| 0
我需要所有的记录与startflag=0后(和)startflag = 4行作为路径(Postgis Linestring在geom)的时间戳顺序,直到和没有下一个startflag=4
从下一个开始标志=4,然后下一个路径,依此类推.
我试过铅和分区,但我不太了解它

fjnneemd

fjnneemd1#

和往常一样,有几种可能的方法可以获得你想要的东西。下面的SQL语句只是其中之一:

WITH reorder AS (
  SELECT id, car, timestamp
  , row_number() OVER (PARTITION BY car ORDER BY timestamp) AS tcid
  , count(*) OVER (PARTITION BY car) AS max_tcid
  , geom, startflag 
  FROM mytable
), trackranges AS (
  SELECT car, tcid AS tcid_start
  , COALESCE(LEAD(tcid, 1) OVER (partition by car order by timestamp) - 1, max_tcid) AS tcid_last
  FROM reorder
  WHERE startflag = 4
)
SELECT car, tcid_start, ST_MakeLine(geom ORDER BY tcid) AS geom
FROM trackranges AS tr
JOIN reorder AS ro USING (car)
WHERE ro.tcid BETWEEN tr.tcid_start AND tr.tcid_last
GROUP BY car, tcid_start
HAVING count(*) > 1
ORDER BY car, tcid_start;

字符串
一些评论:

  • CTE“reorder”为每辆车分配序列号,按时间戳排序(列“tcid”)。这实际上是多余的,但稍后使用整数代替时间戳是我个人的偏好;
  • CTE“reorder”的要点是增加每节车厢的总行数(存储为“max_tcid”),稍后将在COALESCE函数中使用;
  • CTE“trackranges”选择任何汽车的所有起点(startflag = 4),并使用LEAD函数获取该汽车下一个起点的“tcid”;
  • 然而,当前轨道的最后一个点将具有等于“下一开始tcid减1”的tcid,因此需要递减LEAD结果(并且这对于列“tcid”中的连续数字序列比对于时间戳容易得多);
  • 任何汽车的最后一个起点将没有“下一个起点”(LEAD函数将返回NULL,从中减去1,但仍然产生NULL),在这种情况下,先前计算的“tcid_last”开始起作用;
  • CTE“trackranges”因此只产生3列:汽车标识和第一个和最后一个“tcid”用于每个linestring;
  • 主SELECT基于汽车识别来连接两个CTE,使用来自“trackranges”的“tcid_start”列来识别每个单独的轨道,仅添加来自“reorder”的具有tcid在tcid_start和tcid_last之间的那些点;
  • 所收集的数据按车厢和轨道分组,其中几何形状被聚合成一个线串(按tcid排序,tcid又按时间戳排序);
  • 如果任何车厢的最后一个记录是新(不完整)轨道的起点,则结果线串将无效(仅包含单个点)。HAVING子句可防止这种情况,确保仅处理具有多于1个点的组。
zbdgwd5y

zbdgwd5y2#

正如所说:有更多的方法可以达到同样的结果。这一个可能有点困惑,但它的工作:

WITH reorder AS (
  SELECT id, car, timestamp
  , row_number() OVER (PARTITION BY car ORDER BY timestamp) AS tcid
  , geom, startflag 
  FROM mytable
), tracks AS (
  SELECT car, tcid, ROW_NUMBER() OVER (PARTITION BY car ORDER BY tcid) AS track, geom
  FROM reorder
  WHERE startflag = 4
UNION ALL
  SELECT car, tcid, tcid - ROW_NUMBER() OVER (PARTITION BY car ORDER BY tcid) AS track, geom
  FROM reorder
  WHERE startflag <> 4
)
SELECT car, track, ST_MakeLine(geom ORDER BY tcid) AS geom
FROM tracks
GROUP BY car, track
HAVING count(*) > 1
ORDER BY car, track;

字符串
一些解释:

  • CTE“reorder”为每辆车的所有收集点添加连续的数字序列,存储为“tcid”(不需要计算“tcid_last”);
  • CTE“轨道”的第一部分仅收集来自前一CTE的起始点(startflag = 4),并为每个轿厢分配从1开始的新序列号(用作轨道号)(由PARTITION BY处理);
  • 在UNION ALL之后,CTE的第二部分“跟踪”收集所有非起始点(startflag <> 4),并为获得的记录分配一个新的连续序列号,每个车厢从1开始;
  • 从在CTE“重新排序”中获得的旧“tcid”中减去所得到的序列号,得到对应于CTE“轨道”的第一部分(UNION ALL之前)中的重新分配的轨道号的轨道号;
  • 在最后的主查询中,轨迹可以再次按汽车和轨迹进行分组,将点聚合到一个线串中,并使用HAVING子句消除所有只有1个点的轨迹。

为什么它会起作用?
假设我们从以下记录(缩写列列表)开始:

car  | tcid | flag
-------------------
test1 | 1    | 4
test1 | 2    | 0
test1 | 3    | 0
test1 | 4    | 4
test1 | 5    | 0


显然,汽车'test1'有2个轨道,从tcid 1和4开始,因此CTE的第一部分“轨道”将导致下表(其中列“轨道”填充有新的数字序列,从1开始):

car  | tcid | track
-------------------
test1 | 1    | 1
test1 | 4    | 2


第二部分将(暂时)包含以下值:

car  | tcid | row_number | tcid - row_number AS track
------------------------------------------------------
----[tcid 1 is eliminated by the WHERE condition)----
test1 | 2    | 1          | 1
test1 | 3    | 2          | 1
----[tcid 4 is eliminated by the WHERE condition)----
test1 | 5    | 3          | 2


在这个结果列表中,新创建的row_numbers再次形成了一系列连续的数字,但是原始的tcid现在在它们的序列中有了“洞”(当它们的startflag = 4时,一些记录被过滤掉了)。

  • 如果在任何数字序列中没有“洞”,都是从“1”开始的,那么减法将总是“0”(一个常数)
  • 在表的某些部分中,tcid对于每个新记录都以1不断增加,新创建的row_number也以1增加,因此减法再次产生恒定值(直到出现新的“hole”)。换句话说:tcid的2和3是连续的,并且新的row_number 1和2也是连续的,因此减法具有相等的值;
  • 在tcid-序列中存在与轨道开始一样多的“孔”,并且对于每个“孔”,减法产生等于先前轨道号加1的新轨道号(tcid - row_number);
  • 因此,被计算为“tcid-row_number”的列将导致对应于来自CTE的第一部分(UNIONALL之前的部分)的第n轨道的轨道号。

一个警告:如果原始表中插入的第一条记录(无论出于何种原因)没有被标记为起始点,则此查询将创建一个linestring(为该轨道提供足够的点),但将分配一个轨道编号0。这可以在主查询中使用WHERE track > 0轻松消除。

相关问题