2015-05-11 21 views
10

ho dati tavolo comeElimina i record duplicati da una tabella Postgresql senza una chiave primaria?

CREATE TABLE meta.fk_payment1 
(
    id serial NOT NULL, 
    settlement_ref_no character varying, 
    order_type character varying, 
    fulfilment_type character varying, 
    seller_sku character varying, 
    wsn character varying, 
    order_id character varying, 
    order_item_id bigint, 
    .... 
); 

sto inserendo da file CSV in cui tutte le colonne sono gli stessi, invece di colonna id

Nel caso in cui il file CSV caricato più di una volta i dati saranno duplicati.

ma id non lo farà e id è chiave primaria.

quindi voglio rimuovere tutte le righe duplicate senza utilizzare la chiave primaria.

devo fare questo su un'unica tabella

+3

Crea tabella di copia, inserire in newtab selezionare distinto da oldtab. – jarlh

+0

Ho bisogno di farlo su un tavolo singolo –

+2

Sono un po 'confuso riguardo "id è la chiave primaria", ma "rimuovi ... senza usare la chiave primaria". Vuoi dire che non c'è una chiave primaria nel csv, ma nel database ce n'è uno? Dovresti modificare la domanda per essere un po 'più chiara a riguardo. –

risposta

2

Copiare i dati distinti per lavorare tavolo fk_payment1_copy. Il modo più semplice per farlo è quello di utilizzare into

SELECT max(id),settlement_ref_no ... 
INTO fk_payment1_copy 
from fk_payment1 
GROUP BY settlement_ref_no ... 

eliminare tutte le righe da fk_payment1

delete from fk_payment1 

e copiare i dati da fk_payment1_copy tavolo per fk_payment1

insert into fk_payment1 
select id,settlement_ref_no ... 
from fk_payment1_copy 
+0

può essere fatto utilizzando la tabella singola –

+0

@Shubhambatra Non sono sicuro se c'è il modo più semplice. Non puoi creare un nuovo tavolo, vero? – Parado

+0

Posso creare ma in futuro se una qualsiasi colonna diventa chiave esterna non è in grado di eliminare da fk_payment1. È? –

1

Un po 'incerto se il primario parte fondamentale della domanda, ma in ogni caso id non ha bisogno di essere una chiave primaria, ha solo bisogno di essere unico. Come dovrebbe essere dato che è seriale. Quindi, se ha valori univoci, puoi farlo in questo modo:

DELETE FROM fk_payment1 f WHERE EXISTS 
    (SELECT * FROM fk_payment1 WHERE id<f.id 
    AND settlement_ref_no=f.settlement_ref_no 
    AND ...) 

Basta aggiungere tutte le colonne nella query di selezione. In questo modo tutte le righe che hanno gli stessi valori (tranne id) e che seguono questa riga (ordinate per ID) verranno eliminate.

(Inoltre, nominando un tavolo con il prefisso fk_ lo fa apparire come una chiave esterna.)

+0

Io uso questo ma non sta dando un risultato esatto. manca una fila. –

12

Si può fare in questo modo per esempio

DELETE FROM table_name 
    WHERE ctid NOT IN 
    (SELECT  MAX(dt.ctid) 
     FROM  table_name As dt 
     GROUP BY dt.*); 

eseguire questa query

DELETE FROM meta.fk_payment1 
    WHERE ctid NOT IN 
    (SELECT  MAX(dt.ctid) 
     FROM  meta.fk_payment1 As dt 
     GROUP BY dt.*); 
1

se la tabella non è molto grande che si può fare:

-- create temporary table and select distinct into it. 
CREATE TEMP TABLE tmp_table AS 
SELECT DISTINCT column_1, column_2 
FROM original_table ORDER BY column_1, column_2; 

-- clear the original table 
TRUNCATE original_table; 

-- copy data back in again 
INSERT INTO original_table(column_1, column_2) 
SELECT * FROM tmp_table ORDER BY column_1, column_2; 

-- clean up 
DROP TABLE tmp_table 
  • per le tabelle più grandi rimuovere il comando TEMP dalla creazione tmp_table
  • questa soluzione arriva utile quando si lavora con JPA (Hibernate) prodotto @ElementCollection che vengono creati senza chiave primaria.
0

Dunque, c'è un modo giusto nel wiki PG. https://wiki.postgresql.org/wiki/Deleting_duplicates

Questa query esegue questa operazione per tutte le righe di tablename con la stessa colonna1, colonna2 e colonna3.

DELETE FROM tablename 
WHERE id IN (SELECT id 
       FROM (SELECT id, 
          ROW_NUMBER() OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum 
        FROM tablename) t 
       WHERE t.rnum > 1); 

Lo stavo testando su file di 600k di deduplicazione, che portavano a 200k righe univoche. La soluzione che usa group by e NOT IN ha richiesto 3h +, questo richiede 3 secondi.

Problemi correlati