2017-10-21 136 views
0

我在删除重复行时遇到了一些困难。我认为user_id和time_id一起作为一个标识符,但它们甚至有重复。如何删除postgres中的重复项(无唯一标识)

USER_ID(文本),TIME_ID(BIGINT),值1(数字)

user_id; time_id; value1| 
aaa;1;3| 
aaa;1;3| 
aaa;2;4| 
baa;3;1| 

在这种情况下,我怎么删除重复? 因为我在TIME_ID 16个不同的值,并在user_ID的15000分不同的人,我想是这样的,但我没有一个唯一的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) 
+0

几乎*总是*,你的Postgres版本是一个重要的细节。 –

回答

1

请使用上小心删除任何意见,请确保您有必要的话可以“撤销它”。我认为你需要添加一个自动编号列,以协助这项工作

alter table tablename add column is_uniq serial 

然后我会使用ROW_NUMBER(),以帮助确定的行建议你想保留(其中RN = 1)和那些被删除(其中r> 1)。使用以下内容作为指南:

select * 
    , ROW_NUMBER()over(partition by user_id, time_id, value1 order by is_uniq) as rn from tablename 

我不知道是否有任何其他列(S)为按顺序使用,但如果有,那么你可以包括到过条款也是如此。

一旦你有“is_uniq”列和rn> 1行,你应该能够安全地删除不需要的行。

+0

*先备份表格*。使用'\ copy tablename'作为'psql'中的'tablename-before-delete.csv''是一种简单的方法。 –

2

Postgres中的每个表都有几个隐藏的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)上创建主键或为此创建一个新的唯一列。

+0

可以,但一般不应该。对于新手来说,这可能不是最好的建议,尽管它非常有效。 –

+0

它很简单,清楚,*完全有效*所以它不应该被使用? – klin

+0

因为'ctid'并不是真正的公共接口,所以它是非标准的实现细节。并没有什么能够阻止PostgreSQL在未来的版本中改变事物的方式,以突破或者更糟糕的方式打破这个查询。 –

0

如果你不想依靠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;