重复的行 - 如何删除一个?

Mat*_*att 5 postgresql duplication

我有一个包含 OS MasterMap 数据的非常大的表(约 1.14 亿行)。这是新表中新加载的数据。尝试设置主键时,出现此错误:

ERROR:  could not create unique index "tbl_os_mmap_topoarea_pkey"
DETAIL:  Key (toid)=(1000000004081308) is duplicated.
Run Code Online (Sandbox Code Playgroud)

不知何故,我最终得到了一个完全重复的行。这两行中的每个字段都相同。我想删除一行,但保留另一行。由于无法区分两者,如何做到这一点?

我想尽快和尽可能简单地做到这一点。创建临时表等并不是一个真正的选择,因为在这种大小的数据集上需要太长时间。我猜创建一个新的唯一 ID 列会更快,但也可能需要一些时间。

经过一番研究,我了解到 postgres 中的所有记录都有一个隐藏的唯一 ID,即 ctid。我可以用它来删除重复的行之一吗?

ype*_*eᵀᴹ 10

我认为这会起作用:

with d as 
  ( select ctid, row_number() over (partition by t.*) as rn 
    from tablename as t 
  ) 
delete from tablename as t 
using d 
where d.rn > 1 
  and d.ctid = t.ctid ;
Run Code Online (Sandbox Code Playgroud)

还有另一种变体。不确定哪个更有效:

delete from tablename as t 
where exists 
      ( select * 
        from tablename as d 
        where d.ctid > t.ctid 
          and d.* is not distinct from t.*
      ) ;
Run Code Online (Sandbox Code Playgroud)

但请注意文档所说的内容ctid

ctid

行版本在其表中的物理位置。请注意,虽然ctid可用于非常快速地定位行版本,但如果行ctid被更新或移动,则行将发生更改VACUUM FULL。因此ctid作为长期行标识符是无用的。应该使用OID,甚至更好的是用户定义的序列号来标识逻辑行。

因此,如果该表已创建WITH OIDS,请改用它。