2010-09-08 4 views
13

Ho una tabella di dati e ci sono molte voci duplicate dagli invii degli utenti.Rimuovere le righe duplicate lasciando solo la riga più vecchia?

Voglio eliminare tutte le righe duplicate basate sul campo subscriberEmail, lasciando solo l'invio originale.

In altre parole, voglio cercare tutte le e-mail duplicate e cancellare quelle righe, lasciando solo l'originale.

Come posso fare questo senza scambiare le tabelle?
La mia tabella contiene ID univoci per ogni riga.

+0

Si dovrebbe segna una risposta come "accettata" :-) – watery

risposta

27

Dal momento che si sta utilizzando la colonna id come un indicatore di cui record è 'originale':

delete x 
from myTable x 
join myTable z on x.subscriberEmail = z.subscriberEmail 
where x.id > z.id 

Questo lascerà un record per l'indirizzo e-mail.

Modifica per aggiungere:

Per spiegare la query di cui sopra ...

L'idea è quella di partecipare al tavolo contro se stessa. Fai finta di avere due copie del tavolo, ognuna con un nome diverso. Quindi puoi confrontarli tra loro e trovare l'id più basso o per ciascun indirizzo email. Poi vedresti i record duplicati che sono stati creati in seguito e potresti eliminarli. (Stavo visualizzando Excel quando pensavo a questo.)

Per fare quell'operazione su un tavolo, confrontarlo con se stesso ed essere in grado di identificare ciascun lato, si usano gli alias di tabella. x è un alias di tabella. È assegnato nella clausola from in questo modo: from <table> <alias>. x può ora essere utilizzato altrove nella stessa query per fare riferimento a tale tabella come collegamento.

delete x avvia la query con la nostra azione e destinazione. Eseguiremo una query per selezionare record da più tabelle e vogliamo eliminare i record visualizzati in x.

Gli alias vengono utilizzati per fare riferimento a entrambe le "istanze" della tabella. from myTable x join myTable z on x.subscriberEmail = z.subscriberEmail urta il tavolo contro se stesso dove le e-mail corrispondono. Senza la clausola where che segue, ogni record verrebbe selezionato in quanto potrebbe essere unito a se stesso.

La clausola where limita i record selezionati. where x.id > z.id consente l'alias "istanza" x per contenere solo i record che corrispondono ai messaggi di posta elettronica ma hanno un valore superiore id. I dati che vuoi veramente nella tabella, gli indirizzi e-mail univoci (con l'id più basso) non faranno parte di x e non saranno cancellati. Gli unici record in x saranno record duplicati (indirizzi di posta elettronica) con un valore superiore a id rispetto al record originale per tale indirizzo di posta elettronica.

Il join e dove clausole potrebbero essere combinati in questo caso:

delete x 
    from myTable x 
    join myTable z 
    on x.subscriberEmail = z.subscriberEmail 
     and x.id > z.id 

Per evitare duplicati, considerare la colonna subscriberEmail una colonna indicizzata UNICO.

+0

Ehi, non capisco cosa sia X in questo, e dove viene immessa la data. Potrei usare l'ID poiché c'è un ID primario impostato per ciascuna o data. L'ID sembra più facile –

+0

Ehi, ha funzionato !!! Ho cambiato "createdOn" in "id" e presto! haha grazie - Heres il codice che ho usato in PHP: mysql_query ("delete x da my_table x unirsi z my_table su x.subscriberEmail = z.subscriberEmail dove x.id> z.id") or die (mysql_error ()); –

+0

Puoi spiegare come leggere questo codice in inglese - Aiuta essere in grado di leggere logicamente qualcosa per capire la sintassi - Inoltre, ora come faccio a prevenire i duplicati in primo luogo? Sto già usando Insert IGNORE ma non ignoro –

0

Se si dispone di un ID univoco per ogni riga, è possibile provare qualcosa di simile. Non chiedermi perché hai esattamente bisogno della seconda istruzione select, mysql non mi permetterà di eseguire altrimenti. Inoltre, raggruppa in base a qualsiasi colonna i tuoi risultati sono unici.

delete from my_table where id in (
    select id from (
    select id from my_table a group by subscriberEmail having count(*) > 1 
) b 
); 
+1

Credo che questo eliminerebbe tutti, non solo gli extra. – Fosco

+0

No, non lo farebbe. Il gruppo raggrupperà come file da subscriberEmail. Quindi verrà selezionato un abbonato con più di 1 email (conteggio (*)> 1). A questo punto hai praticamente un set di record distinti di abbonati con più di 1 email. Prendi l'ID da questo set di record ed eliminalo. L'ho provato e funziona come un fascino. –

+0

L'esecuzione di questo codice genera un errore "# 1064 - Si è verificato un errore nella sintassi SQL; controllare il manuale corrispondente alla versione del server MySQL per la sintassi corretta da utilizzare vicino a" "alla riga 2" - Codice sotto –

1

Come su questo, ora non si dispone creare le tabelle temporanee con sé unisce

DELETE u1 FROM users u1, users u2 WHERE u1.id < u2.id AND u1.email = u2.email 

Per controllare se ci sono record duplicati nella tabella

SELECT count(*) as Count, email FROM users u group by email having Count > 1