2017-10-21 137 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;