【问题标题】:Postgres how to keep the newest copy based on a column and delete older recordsPostgres如何根据列保留最新副本并删除旧记录
【发布时间】:2020-06-06 03:16:42
【问题描述】:

我有一个事实表不断插入大量记录。它用于另一个表中原始记录的 ML 预测结果。由于插入的频率非常高,我想在插入新批次的结果之前只保留最后一批的预测结果。如何编写查询以删除旧记录,同时只保留每个 record_id 的最新副本?

+--------+-----------+------------+------------+
| row_id | record_id | prediction | insert_ts  |
+--------+-----------+------------+------------+
|      1 |       101 | cat        | 2020-06-04 |
|      2 |       102 | dog        | 2020-06-04 |
|      3 |       103 | tiger      | 2020-06-04 |
|      4 |       101 | tiger      | 2020-06-05 |
|      5 |       102 | lion       | 2020-06-05 |
|      6 |       101 | dog        | 2020-06-06 |
+--------+-----------+------------+------------+

在我运行查询后,表中应该有以下内容。

+--------+-----------+------------+------------+
| row_id | record_id | prediction | insert_ts  |
+--------+-----------+------------+------------+
|      3 |       103 | tiger      | 2020-06-04 |
|      5 |       102 | lion       | 2020-06-05 |
|      6 |       101 | dog        | 2020-06-06 |
+--------+-----------+------------+------------+

我发现一些帖子建议截断表格并插入最新的记录。但这会弄乱 serial 的 row_id 并在其他表中用作外键引用。我该如何编写这个delete 查询?

【问题讨论】:

  • 你为什么不创建一个新表。
  • @zealous 如何保留剩余记录的旧 row_id 以及 row_id 的序列 nextval?

标签: sql postgresql


【解决方案1】:

您可以使用row_number()获取最新记录。您可以使用以下查询创建一个仅包含最新日期记录的新表。

这里是demo。

select
   row_id,
   record_id,
   prediction,
   insert_ts
from
(
  select
    *,
    row_number() over (partition by record_id order by insert_ts desc) as rnk
  from myTable
) val
where rnk = 1

输出:

| row_id | record_id | prediction | insert_ts  |
| ------ | --------- | ---------- | ---------- |
| 3      | 103       | tiger      | 2020-06-04 |
| 5      | 102       | lion       | 2020-06-05 |
| 6      | 101       | dog        | 2020-06-06 |

您也可以在代码中处理此逻辑,在现有record_id 上进行新更新,然后删除旧的并插入新的或覆盖它。

【讨论】:

  • 存在同名表时如何创建表?
  • @ddd 你试过上面的解决方案了吗?你的意思是同名的表?
【解决方案2】:
with keep_these as
(
 select distinct first_value(row_id)
   over (partition by record_id order by insert_ts desc) as rid 
 from tbl
) 
delete from tbl where row_id not in (select rid from keep_these);

【讨论】:

    【解决方案3】:

    当一条记录的命运取决于其他记录的存在时,你可以使用EXISTS():


    DELETE FROM the_table d
    WHERE EXISTS (                      -- a record exists
        SELECT * FROM the_table x
        WHERE x.record_id = d.record_id -- with the same record_id
        AND x.insert_ts  > d.insert_ts  -- but with a newer timestamp
        ); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-20
      • 2017-05-24
      • 2019-08-08
      • 1970-01-01
      • 2020-05-14
      • 2020-05-06
      • 2012-10-28
      • 1970-01-01
      相关资源
      最近更新 更多