删除 Postgresql 中的冗余时间戳范围

Posted

技术标签:

【中文标题】删除 Postgresql 中的冗余时间戳范围【英文标题】:Delete redundant timestamp ranges in Postgres SQL 【发布时间】:2019-06-17 09:16:10 【问题描述】:

我有一个表,其中包含每个文件的文件名和多个时间戳范围,例如如下:

       filename           mindatetime                 maxdatetime
    monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 11:00:00 AM
    monitor_4.dat   2019-04-28 11:00:00 AM      2019-04-29 18:00:00 PM
    monitor_4.dat   2019-04-28 09:30:00 AM      2019-04-29 23:00:00 PM
    monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 10:00:00 AM
    monitor_5.dat   2019-04-28 02:00:00 PM      2019-04-28 06:00:00 PM
    monitor_5.dat   2019-04-28 09:00:00 AM      2019-04-28 03:00:00 PM
    monitor_7.dat   2019-04-21 03:06:26.0 AM    2019-05-21 03:06:10.0 AM
    monitor_7.dat   2019-05-21 03:06:10.001 AM  2019-05-24 03:06:11.0 AM
    monitor_7.dat   2019-06-05 03:06:18.001 AM  2019-06-06 03:06:11.0 AM
    monitor_7.dat   2019-05-24 03:06:11.001 AM  2019-06-05 03:06:18.0 AM
    monitor_7.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
    monitor_7.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

我需要删除多余的时间戳范围,即>属于给定时间戳范围内的那些。 在这种情况下,对于文件“monitor_5.dat”,我们需要将 mindatetime 设置为 7AM,将 maxdatetime 设置为 6PM,因为它们构成了涵盖其他条目的逻辑最小和最大时间戳范围。

所以我的结果输出应该是这样的:

   filename           mindatetime                 maxdatetime
monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 23:00:00 PM
monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 06:00:00 PM
monitor_7.dat   2019-04-21 03:06:26.0 AM    2019-06-05 03:06:18.0 AM
monitor_7.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
monitor_7.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

这需要仅通过 SQL 来实现。任何的意见都将会有帮助。我已经探索过 Postgres 中提供的“tsrange”功能,但这并没有完全帮助我。

【问题讨论】:

您的样本结果有误。你对待2019-05-21 03:06:10.001 AM2019-05-21 03:06:10.0 一样。 【参考方案1】:

此答案仅适用于 PostgreSQL;你是故意给 mysql 打标签的吗?

您必须将表与自身连接并删除其他条目中包含的条目:

DELETE FROM mytable AS a
USING mytable AS b
WHERE a.filename = b.filename
  AND tsrange(a.mindatetime, a.maxdatetime) <@ tsrange(b.mindatetime, b.maxdatetime)
  AND (a.ctid, a.xmin::text) <> (b.ctid, b.xmin::text);

最后一个条件防止将一行与其自身进行比较。

【讨论】:

【参考方案2】:

这是一种差距和孤岛问题。我建议找出“重叠”发生的位置,然后使用累积和来识别组。累积的max() 适用于此:

select filename, min(mindatetime) as mindatetime,
       max(maxdatetime) as maxdatetime
from (select t.*,
             sum(case when prev_maxdatetime >= mindatetime then 0 else 1 end) over
                 (partition by filename order by mindatetime) as grp
      from (select t.*,
                   max(maxdatetime) over
                       (partition by filename
                        order by mindatetime
                        rows between unbounded preceding and 1 preceding
                       ) as prev_maxdatetime
            from t
           ) t
     ) t
group by filename, grp;

最里面的子查询确定非重叠时间范围的开始位置。中间查询然后对这些“开始”进行累积总和,以将分组标识符分配给每个组。然后,外部查询按此组(和文件名)聚合。

您可以运行内部查询并查看它们产生的值。

Here 是一个 dbfiddle。就我而言,根据您在here提出的问题,这可以正常工作。如果您想考虑值相同/重叠的时间滞后,请提出一个问题,并清楚地解释您的逻辑。

编辑:

如果您希望每个文件名有一条记录,那么只需使用聚合:

select filename, min(mindatetime) as mindatetime,
       max(maxdatetime) as maxdatetime
from t
group by filename;

第一个版本组合了它们之间没有间隙的行。这只需要最早和最晚的日期/时间。

【讨论】:

这个逻辑对我有用。能否请您简要解释一下此查询的目的是什么 文件名“monitor_7.dat”失败 @Abhilash28Abhi 。 . .首先“失败”并不能很好地描述正在发生的事情,因此没有办法提供帮助。毫无疑问,问题在于时间戳的毫秒数。确保您的时间戳正确表示它们。 我的意思是它没有为这种情况提供单个输出,而是返回该 systemId 的所有行。我现在添加这个的原因是因为表中的记录很大,我很难一次添加所有场景。 好吧..这不是那么直截了当。我已经包含了不连续的记录,对于这些记录,最小和最大逻辑将无法正常工作

以上是关于删除 Postgresql 中的冗余时间戳范围的主要内容,如果未能解决你的问题,请参考以下文章

在 PostgreSQL 中使用带时间戳的 BETWEEN

每天选择特定时间范围的时间戳数据

使用日期和值从传感器中删除冗余数据

PostgresQL + Spring JPA:org.postgresql.util.PSQLException:错误:无法将类型 bytea 转换为没有时区的时间戳

如何从 SQLite3 和 PostgreSQL 中的时间戳中选择日期

HSQLDB 中的 Postgresql 时间戳和未来默认值