PostgreSQL 删除重复数据
我们常常会遇到这样的问题,就是数据重复。然后我们需要对重复数据进行删除。保留最大还是最小则根据具体业务来判断。
假设有表 vbi1 在设计表的时候由于 vbi01 没有被设置为主键,这个时候业务发现 vbi01 重复了,我们需要根据字段 vbi01 来删除重复的 vbi01,保留最早或者最近插入的数据行。
这里我们不得不讲一个关于 PostgreSQL 的知识点,就是即使表在没有设置主键的情况下,PostgreSQL 在底层数据实现上会有一个默认的 CTID 值。
cloud_test=# select ctid,vaf01 from vaf1;
ctid | vaf01
-------+--------------------
(0,1) | 934376602115133442
(0,2) | 934376602115133441
(0,3) | 934376602115133440
(0,4) | 932591980117118979
(0,5) | 932591980117118978
(0,6) | 932591980117118977
(6 rows)
cloud_test=#
备注:这里的 ctid 就是行在底层存储的唯一标识。
需求:对表中重复的数据进行删除保留最小的 CTID 或者最大的 CTID 值。
CREATE INDEX IF NOT EXISTS ix_vbi1_vbi01 ON public.vbi1 USING BTREE(vbi01);
首先我们需要在重复值的字段上创建一个索引,这可以帮助提高删除重复数据的执行效率。
DELETE FROM vbi1 a WHERE a.ctid <> (SELECT min(b.ctid) FROM vbi1 b WHERE a.vbi01 = b.vbi01);
UPDATE vbi1 SET vbi01 = (-1)*vbi1.vbi01 FROM vbi1 b WHERE vbi1.vbi01 = b.vbi01 AND vbi1.ctid < b.ctid
DROP INDEX IF EXISTS ix_vbi1_vbi01;
ALTER TABLE vbi1 ADD PRIMARY KEY(vbi01);
说明:执行删除还是将重复数据前加 - 号根据场景取舍,最后设置表字段为主键或者唯一索引都可以避免后续的数据重复。