如何删除 postgres 中的重复项(没有唯一 ID)
How to remove duplicates in postgres (no unique id)
我在删除重复行时遇到一些困难。我认为 user_id 和 time_id 一起充当标识符,但它们甚至有重复项。
user_id(文本),time_id(bigint),value1(数字)
user_id; time_id; value1|
aaa;1;3|
aaa;1;3|
aaa;2;4|
baa;3;1|
在这种情况下,我该如何删除重复项?
由于我在 time_id 中有 16 个不同的值,在 user_id 中有 15,000 个不同的值,我尝试了类似的方法,但我没有唯一的 ID..
DELETE FROM tablename a
USING tablename b
WHERE a.unique_id < b.unique_id
AND a.user_id = b.user_id
time_id = 1 (repeat till time_id 16)
请谨慎使用有关删除的任何建议,确保您有办法 "undo it" 如果需要。我认为您需要添加一个自动编号的列来协助完成这项工作
alter table tablename add column is_uniq serial
然后我建议使用 row_number() 来帮助识别您确实要保留的行(其中 rn=1)和要删除的行(其中 rn>1)。使用以下内容作为指南:
select *
, ROW_NUMBER()over(partition by user_id, time_id, value1 order by is_uniq) as rn from tablename
我不确定是否有任何其他列可用于 order by,但如果有,那么您也可以将其包含在 over 子句中。
一旦您拥有 "is_uniq" 列和 rn>1 行,您应该能够安全地删除不需要的行。
Postgres 中的每个 table 都有一些隐藏的 system columns。其中之一 (ctid)
根据定义是唯一的,可以在缺少主键的情况下使用。
DELETE FROM tablename a
USING tablename b
WHERE a.ctid < b.ctid
AND a.user_id = b.user_id
AND a.time_id = b.time_id;
问题是因为缺少主键。使用隐藏列不应该是一个系统的方法(见下面的评论)。删除重复项后,您应该在 (user_id, time_id)
上创建一个主键或为此目的创建一个新的唯一列。
如果您不想依赖 ctid
(我个人认为),您可以添加一个唯一的列(例如 serial
)并将其用于标识目的,
CREATE TABLE lutser
( user_id text not null
, time_i integer not null
, value integer not null
);
INSERT INTO lutser(user_id,time_i,value) VALUES
('aaa', 1, 3)
,('aaa', 1, 3)
,('aaa', 2, 4)
,('baa', 3, 1)
;
SELECT*FROM lutser;
ALTER TABLE lutser
ADD COLUMN seq serial NOT NULL UNIQUE
;
SELECT*FROM lutser;
DELETE FROM lutser del
WHERE EXISTS(
SELECT*FROM lutser x
WHERE x.user_id=del.user_id
AND x.time_i=del.time_i
AND x.seq < del.seq
);
ALTER TABLE lutser
ADD PRIMARY KEY (user_id,time_i)
;
SELECT*FROM lutser;
我在删除重复行时遇到一些困难。我认为 user_id 和 time_id 一起充当标识符,但它们甚至有重复项。
user_id(文本),time_id(bigint),value1(数字)
user_id; time_id; value1|
aaa;1;3|
aaa;1;3|
aaa;2;4|
baa;3;1|
在这种情况下,我该如何删除重复项? 由于我在 time_id 中有 16 个不同的值,在 user_id 中有 15,000 个不同的值,我尝试了类似的方法,但我没有唯一的 ID..
DELETE FROM tablename a
USING tablename b
WHERE a.unique_id < b.unique_id
AND a.user_id = b.user_id
time_id = 1 (repeat till time_id 16)
请谨慎使用有关删除的任何建议,确保您有办法 "undo it" 如果需要。我认为您需要添加一个自动编号的列来协助完成这项工作
alter table tablename add column is_uniq serial
然后我建议使用 row_number() 来帮助识别您确实要保留的行(其中 rn=1)和要删除的行(其中 rn>1)。使用以下内容作为指南:
select *
, ROW_NUMBER()over(partition by user_id, time_id, value1 order by is_uniq) as rn from tablename
我不确定是否有任何其他列可用于 order by,但如果有,那么您也可以将其包含在 over 子句中。
一旦您拥有 "is_uniq" 列和 rn>1 行,您应该能够安全地删除不需要的行。
Postgres 中的每个 table 都有一些隐藏的 system columns。其中之一 (ctid)
根据定义是唯一的,可以在缺少主键的情况下使用。
DELETE FROM tablename a
USING tablename b
WHERE a.ctid < b.ctid
AND a.user_id = b.user_id
AND a.time_id = b.time_id;
问题是因为缺少主键。使用隐藏列不应该是一个系统的方法(见下面的评论)。删除重复项后,您应该在 (user_id, time_id)
上创建一个主键或为此目的创建一个新的唯一列。
如果您不想依赖 ctid
(我个人认为),您可以添加一个唯一的列(例如 serial
)并将其用于标识目的,
CREATE TABLE lutser
( user_id text not null
, time_i integer not null
, value integer not null
);
INSERT INTO lutser(user_id,time_i,value) VALUES
('aaa', 1, 3)
,('aaa', 1, 3)
,('aaa', 2, 4)
,('baa', 3, 1)
;
SELECT*FROM lutser;
ALTER TABLE lutser
ADD COLUMN seq serial NOT NULL UNIQUE
;
SELECT*FROM lutser;
DELETE FROM lutser del
WHERE EXISTS(
SELECT*FROM lutser x
WHERE x.user_id=del.user_id
AND x.time_i=del.time_i
AND x.seq < del.seq
);
ALTER TABLE lutser
ADD PRIMARY KEY (user_id,time_i)
;
SELECT*FROM lutser;