删除 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 AM
和2019-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 + Spring JPA:org.postgresql.util.PSQLException:错误:无法将类型 bytea 转换为没有时区的时间戳