有没有办法删除/更新时间序列中的重复值?

Is there a way to delete / update duplicate values in a time sequence?

提问人:SkyWalker 提问时间:10/26/2023 最后编辑:SkyWalker 更新时间:10/27/2023 访问量:67

问:

我有一个看起来像的表(不要介意数据库供应商,因为我在 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

值 in 表示在另行通知之前有效。NULLend

理想情况下,对于表边缘(是的,图形边缘)将有一个查询,该查询将生成第二个摘录的输出。目标是首先删除多余的行,然后更新剩余的最后一行,以匹配第一个已删除的行。startstart

我能得到的最接近的是以下内容,在这里我找到了所有要删除的冗余行:

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

然后,我需要执行更新步骤以使时间序列保持一致。另外,是完全匹配的,它是一个浮点数,但这至少适用于 PostgreSQL。value

如果无法使用 ANSI,我将有兴趣了解 PostgreSQL 案例。

PostgreSQL 算法 ANSI-SQL

评论

0赞 Thorsten Kettner 10/27/2023
我不明白。有一个表,还有带有匹配列的 CSV 数据。然后你说你想删除或更新一些东西。但你真正想做什么?如果是 CSV,则与表或数据库系统无关。是否要将此数据导入到表中?但是将文本文件导入数据库不是 SQL,因此不在 ANSI SQL 中。

答:

2赞 Stefanov.sm 10/27/2023 #1

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

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 标准的版本,不带 .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 演示

评论

0赞 jarlh 11/28/2023
接近标准符合,是保留字,即需要分隔为 .en.wikipedia.org/wiki/List_of_SQL_reserved_wordsvalue"value"
1赞 maraca 10/27/2023 #2

如果日期范围是连续的,我认为最简单(但有点脏)的方法如下:

  1. 重命名表并设置为将来的唯一日期。endnull

  2. 将值放入新的边表中:

     SELECT parent_id, child_id, value, MIN(start), MAX(end)
     FROM edge_old
     GROUP BY parent_id, child_id, value
    
  3. 设置为与您之前设置的唯一日期匹配的位置,并删除旧表。endnull

评论

0赞 maraca 10/27/2023
尽管如果将值设置回以前的值,则范围将是错误的。这有点过于简单化了。但是,在新表中插入所需范围的想法很有帮助,因为编写 select 语句更容易,该语句可以准确地选择所需的内容,而不是更新和删除行。