postgresql 是否有方法删除/更新时间序列中的重复值?

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

我有一个表,它看起来像这样(不要介意数据库供应商,因为我在ANSI SQL中需要它):

create table edge (
   parent_id int not null,
   child_id int not null,
   value float not null,
   start date not null,
   end date not null
)

字符串
然后,我将获得以下CSV输入数据:

1,2,0,2023-01-01,2023-01-10
1,2,0,2023-01-11,2023-01-20
1,2,0,2023-01-21,NULL
1,3,0,2023-01-01,2023-01-10
1,3,0,2023-01-11,2023-01-20
1,3,1,2023-01-21,NULL


请注意,如果父级为1,子级为2,则相同的值0在多个日期间隔中重复,因此它可以折叠为:

1,2,0,2023-01-01,NULL
1,3,0,2023-01-01,2023-01-20
1,3,1,2023-01-21,NULL


end中的值NULL表示有效,直到另行通知。
理想情况下,应该有一个查询,它会为表边缘(是的,图边缘)生成第二个摘录的输出。目标是首先删除冗余行,并使用start更新剩余的最后一行,以匹配第一个删除行的start
我能得到的最接近的是下面的,在这里我找到了所有要删除的冗余行:

SELECT *
FROM edge
WHERE (parent, child, value, start) IN (SELECT parent, child, value, end+1
                                        FROM edge)
ORDER BY parent, child, start


然后我需要做更新步骤来保持时间序列的一致性。另外,value是完全匹配的,它是一个浮点数,但这至少在PostgreSQL上有效。
如果没有办法使用ANSI,我会有兴趣学习PostgreSQL的情况。

ukdjmx9f

ukdjmx9f1#

我首先建议使用一个查询,根据上面的业务规则选择所需的行,可以使用(作为视图?)而不删除。我使用的是非ANSI distinct on PostgreSQL的子句。

select distinct on (parent_id, child_id, value) 
 parent_id, child_id, value, 
 first_value(start_date) over (partition by parent_id, child_id, value order by start_date),
 end_date
from edge;
order by parent_id, child_id, value, start_date desc;

字符串
如果这是不可接受的,则将查询整形为CTE,然后删除不在其中的这些行。
下面是一个符合SQL标准的版本w/o distinct on

select parent_id, child_id, value, sd start_date, end_date
from
(
 select
   row_number() over (partition by parent_id, child_id, value order by start_date desc) rn, 
   parent_id, child_id, value, 
   first_value(start_date) over (partition by parent_id, child_id, value order by start_date) sd,
   end_date
 from edge
) t
where rn = 1;


SQL Fiddle demo

svujldwt

svujldwt2#

如果日期范围是连续的,我认为最简单的(但有点脏)方法如下:
1.将end设置为未来的唯一日期,其中为null
1.将值放入新边表:

SELECT parent_id, child_id, value, MIN(start), MAX(end)
 FROM edge_old
 GROUP BY parent_id, child_id, value

字符串
1.将end设置为null,它与之前设置的唯一日期匹配,并删除旧表。

相关问题