识别非常接近的行组

Posted

技术标签:

【中文标题】识别非常接近的行组【英文标题】:Identify groups of rows in close proximity 【发布时间】:2014-05-20 19:10:56 【问题描述】:

我正在为学校做一个项目,并在一周的课程中获得了一个关于三个人的 GPS 记录的数据库。我正在尝试根据它们之间的时间将这些录音分组为旅行。如果一段录音距离之前的录音在 300 秒内,则将它们视为同一行程的一部分,否则,将它们视为不同行程的一部分。

到目前为止,我已经设法计算出第 n 行的记录与第 n-1 行的记录之间的时间差,我现在正在尝试创建一个用于合并记录介绍行程的函数。这在另一种编程语言中会很容易,但在本课程中,我们使用的是我不太熟悉的 PostgreSQL。

为了解决这个问题,我正在尝试创建一个带有变量的函数,每次两个记录之间的时间差大于 300 秒时该变量都会增加,并根据该变量将每一行分配给一次行程。这是我目前所得到的,尽管目前,变量一直重置 X,因此将所有行分配给行程 1...

CREATE OR REPLACE FUNCTION tripmerge(time_diff double precision)
RETURNs integer AS $$
declare 
X integer := 1;
ID integer;
BEGIN
  IF time_diff < 300 THEN
    ID = X;
  ELSE 
    ID =X;
    X:=X+1;
  END IF;
 RETURN ID;
END;$$ 
LANGUAGE plpgsql;

如何更改X 不会一直重置?我正在使用 PostgreSQL 9.1。

编辑:

这是我正在使用的表格:

curr_rec (timestamp), prev_rec (timestamp), time_diff (double precision)

这是数据集的一个样本:

'2013-11-14 05:22:33.991+01',null ,null
'2013-11-14 09:15:40.485+01','2013-11-14 05:22:33.991+01',13986.494
'2013-11-14 09:17:04.837+01','2013-11-14 09:15:40.485+01',84.352
'2013-11-14 09:17:43.055+01','2013-11-14 09:17:04.837+01',38.218
'2013-11-14 09:23:24.205+01','2013-11-14 09:17:43.055+01',341.15

预期结果会增加一列:

tripID
1
2
2
2
3

我认为这个小提琴应该可以工作:http://sqlfiddle.com/#!1/4e3e5/1/0

【问题讨论】:

triplegs?三胞胎?我已将问题阅读了两次,但仍然不知道您要达到什么目的。请添加:您的 Postgres 版本、表定义(psql 中的\d recordings)、示例数据和结果数据示例——或者更好的是fiddle。 我明白你的意思并编辑了文本以试图澄清我的问题,谢谢:) 可能可以通过单个查询来解决,like this one. 但我仍然没有看到表定义或示例数据或预期结果... 作为一般说明,听起来您正在尝试在关系数据库中为您的问题实施程序解决方案。在关系数据库中使用过程解决方案通常不是一个好主意。重新考虑你的问题。 SQL 是一种声明性 语言;看看你能不能想出一种用 SQL 表达你需要的方法。我还要注意,我的经验是你很少需要在 PostgreSQL 中使用过程代码。它的特性使得在比其他数据库更广泛的问题中找到声明式(纯 SQL)解决方案成为可能 *coughOraclecough*。 Erwin:我添加了所有需要的数据以及我希望从中得到的数据以及小提琴。如果它可以通过一个很好的查询来解决,尽管你链接到的那个对我来说远远超出了我能够解释的程度。 【参考方案1】:

此查询仅使用 curr_rec,而不使用其他冗余的预计算列:

SELECT 1 + count(step OR NULL) OVER (ORDER BY curr_rec) AS trip_id
FROM  (
   SELECT curr_rec
         ,lag(curr_rec) OVER (ORDER BY curr_rec) AS prev_rec
         ,curr_rec - lag(curr_rec) OVER (ORDER BY curr_rec)
                                        > interval '5 min' AS step
   FROM  timestamps
   ) x;

主要特点是:

window function lag(),用于查看上一行是否超过 5 分钟前。 (只需使用interval 进行比较,无需提取秒数) 窗口聚合函数count() - 这只是带有OVER 子句的基本聚合函数。 表达式step OR NULL 只留下TRUENULL,其中只有TRUE 被计入运行计数,从而达到您想要的结果。

SQL Fiddle(在您提供的基础上构建)。

【讨论】:

以上是关于识别非常接近的行组的主要内容,如果未能解决你的问题,请参考以下文章

SQL:查找连续几天不存在的行组

使用 php 编辑文本文件中的行组

人脸识别系统openlr是啥意思?

查找具有已定义结束的连续相同值的行组 (SQL Redshift)

重新加载行数据后,展开的行组保持展开状态

在 s-s-rS 的行组中获取下一个值