Rimuovi le righe duplicate in MySQL


375

Ho una tabella con i seguenti campi:

id (Unique)
url (Unique)
title
company
site_id

Ora, devo rimuovere le righe che hanno lo stesso title, company and site_id. Un modo per farlo sarà utilizzare il seguente SQL insieme a uno script ( PHP):

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

Dopo aver eseguito questa query, posso rimuovere i duplicati utilizzando uno script lato server.

Ma voglio sapere se questo può essere fatto solo usando la query SQL.


1
Domanda veloce: vuoi sempre che non esistano duplicati (titolo, azienda, site_id)? In tal caso, imposterei un vincolo nel database per imporre che il titolo, la società e site_id fossero univoci. Ciò significherebbe che non avresti bisogno di un processo di pulizia. E richiede solo una singola riga di SQL.
J. Polfer,

1
Si prega di fare riferimento a questo link di StackOverflow . Ha funzionato per me come un fascino.

Posso raccomandare questa soluzione (pubblicata in un'altra discussione): stackoverflow.com/a/4685232/195835
Simon East

Puoi anche controllare questa risposta
Jose Rui Santos,

Risposte:


607

Un modo davvero semplice per farlo è aggiungere un UNIQUEindice sulle 3 colonne. Quando scrivi la ALTERdichiarazione, includi la IGNOREparola chiave. Così:

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

Questo eliminerà tutte le righe duplicate. Come ulteriore vantaggio, il futuro INSERTsche sarà duplicato verrà eliminato. Come sempre, potresti voler fare un backup prima di eseguire qualcosa del genere ...


8
Interessante , ma le ipotesi che la clausola IGNORE fa per rimuovere quei duplicati è una preoccupazione che potrebbe non corrispondere alle esigenze. Valori errati che vengono troncati alla corrispondenza accettabile più vicina ti suonano bene?
OMG Pony il

75
Per la cronaca, se si utilizza InnoDB, è possibile che si verifichi un problema, esiste un bug noto relativo all'utilizzo di ALTER IGNORE TABLE con i database InnoDB.
DarkMantis,


42
Per le tabelle InnoDB, eseguire prima la seguente query:set session old_alter_table=1;
shock_one

51
Questo non è più supportato in 5.7.4
Ray Baxter,

180

Se non si desidera modificare le proprietà della colonna, è possibile utilizzare la query seguente.

Dato che hai una colonna con ID univoci (ad es. auto_incrementColonne), puoi usarla per rimuovere i duplicati:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

In MySQL, puoi semplificarlo ancora di più con l' operatore NULL-safe equal (noto anche come "operatore di astronave" ):

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;

3
questa soluzione non funziona correttamente, ho provato a fare alcuni record duplicati e fa qualcosa di simile (20 righe interessate) ma se la esegui di nuovo ti mostrerà (4 righe interessate) e così via fino a raggiungere (0 righe interessate) che è un po 'sospetto e qui è ciò che funziona meglio per me, è quasi lo stesso ma funziona in una corsa, ho modificato la soluzione
Nassim

1
@Nassim: Devi fare qualcosa di diverso da questa risposta perché funziona perfettamente per me (in MySQL).
Lawrence Dol,

3
Per chiunque fosse confuso come me, i termini di confronto NULL sono necessari perché NULL non è uguale a NULL in MySQL. Se si garantisce che le colonne pertinenti non sono NULL, è possibile escludere questi termini.
Ian,

3
Sì, la risposta accettata non è più valida, dal momento che MYSQL 5.7 dovrebbe quindi essere la risposta accettata in quanto è universale e non richiede nemmeno la creazione di tabelle temporanee.
that-ben

1
MOLTO LENTO se ci sono MOLTE copie di un dato record (ad esempio 100 da ridurre a 1) e molti record con quella condizione. Consiglia invece stackoverflow.com/a/4685232/199364 . IMHO, SEMPRE utilizzare l'approccio collegato; è una tecnica intrinsecamente più veloce.
ToolmakerSteve

78

MySQL ha delle restrizioni riguardo al riferimento alla tabella da cui stai eliminando. Puoi aggirare questo con una tabella temporanea, come:

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

Dal suggerimento di Kostanos nei commenti:
L'unica query lenta sopra è DELETE, per i casi in cui hai un database molto grande. Questa query potrebbe essere più veloce:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id

3
@andomar, funziona benissimo tranne quando uno dei campi nella clausola where contiene null. Esempio: sqlfiddle.com/#!2/983f3/1
un programmatore

1
L'Insert SQL è costoso? Mi chiedo perché scade nel mio database MySQL.
Cassio,

4
L'unica query lenta qui è quella DELETE, nel caso in cui si disponga di un database di grandi dimensioni. Questa query potrebbe essere più veloce:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos l'

@Kostanos Non solo DELETE, ma anche INSERTal tavolo temporaneo, mi ci è voluto molto tempo. Quindi un indice per la tabella tmp potrebbe essere di grande aiuto create index tmpTable_id_index on tmpTable (id), almeno per me.
Jiezhi.G

1
Se i tuoi tavoli sono grandi, vale la pena aggiungere un indice con: -create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke

44

Se la IGNOREdichiarazione non funziona come nel mio caso, puoi usare la seguente dichiarazione:

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;

1
funziona benissimo se hai impostazioni innoDB con vincolo di chiave esterna.
Magdmartin,

@magdmartin, ma i vincoli esterni non impediranno l'eliminazione della tabella?
Basilevs,

1
La dichiarazione IGNORE non ha funzionato per me e questo ha funzionato benissimo nel dedurre 5 milioni di dischi. Saluti.
Mauvis Ledford,

32

L'eliminazione dei duplicati sulle tabelle MySQL è un problema comune, che è in genere il risultato di un vincolo mancante per evitare prima quei duplicati. Ma questo problema comune di solito comporta esigenze specifiche ... che richiedono approcci specifici. L'approccio dovrebbe essere diverso a seconda, ad esempio, della dimensione dei dati, della voce duplicata che dovrebbe essere mantenuta (generalmente la prima o l'ultima), se ci sono degli indici da conservare o se vogliamo eseguire ulteriori azione sui dati duplicati.

Ci sono anche alcune specificità su MySQL stesso, come non essere in grado di fare riferimento alla stessa tabella su una causa FROM quando si esegue un aggiornamento della tabella (genererà l'errore MySQL # 1093). Questa limitazione può essere superata utilizzando una query interna con una tabella temporanea (come suggerito in alcuni approcci sopra). Ma questa query interna non funzionerà particolarmente bene quando si ha a che fare con origini di big data.

Tuttavia, esiste un approccio migliore per rimuovere i duplicati, che è sia efficiente che affidabile e che può essere facilmente adattato alle diverse esigenze.

L'idea generale è quella di creare una nuova tabella temporanea, in genere aggiungendo un vincolo univoco per evitare ulteriori duplicati, e INSERIRE i dati dalla tabella precedente a quella nuova, occupandosi dei duplicati. Questo approccio si basa su semplici query INSERT di MySQL, crea un nuovo vincolo per evitare ulteriori duplicati e ignora la necessità di utilizzare una query interna per cercare duplicati e una tabella temporanea che dovrebbe essere mantenuta in memoria (adattando quindi anche le origini di big data).

Ecco come può essere raggiunto. Dato che abbiamo un impiegato di tabella , con le seguenti colonne:

employee (id, first_name, last_name, start_date, ssn)

Per eliminare le righe con una colonna ssn duplicata e mantenere solo la prima voce trovata, è possibile seguire la seguente procedura:

-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;

-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);

-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;

-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

Spiegazione tecnica

  • La riga n. 1 crea una nuova tabella tmp_eployee con la stessa struttura della tabella degli impiegati
  • La riga 2 aggiunge un vincolo UNICO alla nuova tabella tmp_eployee per evitare ulteriori duplicati
  • La riga n. 3 esegue la scansione della tabella dei dipendenti originale per ID, inserendo nuove voci dei dipendenti nella nuova tabella tmp_eployee , ignorando le voci duplicate
  • La riga n. 4 rinomina le tabelle, in modo che la nuova tabella dei dipendenti contenga tutte le voci senza i duplicati e una copia di backup dei dati precedenti venga conservata nella tabella backup_employee

Usando questo approccio, i registri 1.6M sono stati convertiti in 6k in meno di 200s.

Chetan , seguendo questo processo, puoi velocemente e facilmente rimuovere tutti i tuoi duplicati e creare un vincolo UNICO eseguendo:

CREATE TABLE tmp_jobs LIKE jobs;

ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);

INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;

RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

Naturalmente, questo processo può essere ulteriormente modificato per adattarlo alle diverse esigenze durante l'eliminazione dei duplicati. Seguono alcuni esempi.

✔ Variazione per mantenere l'ultima voce anziché la prima

A volte è necessario mantenere l'ultima voce duplicata anziché la prima.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Nella riga n. 3, la clausola DESC di ORDER BY id fa in modo che gli ultimi ID abbiano la priorità sugli altri

✔ Variazione per l'esecuzione di alcune attività sui duplicati, ad esempio mantenendo un conteggio sui duplicati trovati

A volte è necessario eseguire ulteriori elaborazioni sulle voci duplicate che si trovano (come tenere un conteggio dei duplicati).

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Alla riga 3, una nuova colonna n_duplica viene creata
  • Alla riga 4, la query INSERT INTO ... ON DUPLICATE KEY UPDATE viene utilizzata per eseguire un aggiornamento aggiuntivo quando viene trovato un duplicato (in questo caso, aumentando un contatore) INSERT INTO ... ON DUPLICATE KEY UPDATE query può essere utilizzato per eseguire diversi tipi di aggiornamenti per i duplicati trovati.

✔ Variazione per la rigenerazione dell'ID campo auto-incrementale

A volte utilizziamo un campo auto-incrementale e, per mantenere l'indice il più compatto possibile, possiamo sfruttare l'eliminazione dei duplicati per rigenerare il campo auto-incrementale nella nuova tabella temporanea.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Alla riga 3, invece di selezionare tutti i campi nella tabella, il campo ID viene ignorato in modo che il motore DB ne generi automaticamente uno nuovo

✔ Ulteriori variazioni

Molte altre modifiche sono anche possibili a seconda del comportamento desiderato. Ad esempio, le seguenti query useranno una seconda tabella temporanea per, oltre a 1) mantenere l'ultima voce invece della prima; e 2) aumentare un segnalino sui duplicati trovati; anche 3) rigenerare l'id del campo auto-incrementale mantenendo l'ordine di immissione come sui dati precedenti.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

CREATE TABLE tmp_employee2 LIKE tmp_employee;

INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;

DROP TABLE tmp_employee;

RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;

27

C'è un'altra soluzione:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...

4
In che modo differisce dalla risposta di @ rehriff, che ha presentato 6 mesi prima?
Lawrence Dol,

@LawrenceDol Immagino sia un po 'più leggibile e penso anche che la sua risposta non fosse la stessa nel momento in cui ho risposto e penso che la sua risposta sia stata modificata.
Mostafa -T,

1
hmm. Ci vuole troppo tempo mentre il numero di dischi non era grande!
SuB,

8

se si dispone di una tabella di grandi dimensioni con un numero enorme di record, le soluzioni di cui sopra non funzioneranno o impiegheranno troppo tempo. Quindi abbiamo una soluzione diversa

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;

6

Ho questa query snipet per SQLServer ma penso che possa essere utilizzata in altri DBMS con piccole modifiche:

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

Ho dimenticato di dirti che questa query non rimuove la riga con l'ID più basso delle righe duplicate. Se questo funziona per te prova questa query:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)

Non funzionerà se ci sono più di due duplicati di un gruppo.
OMG Pony il

11
Sfortunatamente, MySQL non ti consente di selezionare dalla tabella da cui stai eliminandoERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar

1
Per risolvere l' "You can't specify target table 'Table' for update in FROM..."errore, usa: DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)che forza MySQL a creare una tabella temporale. Tuttavia è molto lento in set di dati di grandi dimensioni ... in questi casi, consiglierò il codice di Andomar, che è molto più veloce.
lepe,

6

Il modo più veloce è inserire righe distinte in una tabella temporanea. Utilizzando Elimina, mi ci sono volute alcune ore per rimuovere i duplicati da una tabella di 8 milioni di righe. Utilizzando insert e distinto, ci sono voluti solo 13 minuti.

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  

1
La tua quarta riga dovrebbe dire TRUNCATE TABLE tableNamee la quinta riga dovrebbe direINSERT INTO tableName SELECT * FROM tempTableName;
Sana

5

Una soluzione semplice da capire e che funziona senza chiave primaria:

1) aggiungi una nuova colonna booleana

alter table mytable add tokeep boolean;

2) aggiungere un vincolo alle colonne duplicate E alla nuova colonna

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) imposta la colonna booleana su true. Ciò avrà esito positivo solo su una delle righe duplicate a causa del nuovo vincolo

update ignore mytable set tokeep = true;

4) eliminare le righe che non sono state contrassegnate come mantenimento

delete from mytable where tokeep is null;

5) rilasciare la colonna aggiunta

alter table mytable drop tokeep;

Ti suggerisco di mantenere il vincolo che hai aggiunto, in modo da evitare nuovi duplicati in futuro.


1
Questo ha funzionato davvero bene in mysql 5.7, dove la soluzione accettata non funziona più
Robin31,

5

Elimina le righe duplicate utilizzando l'istruzione DELETE JOIN MySQL ti fornisce l'istruzione DELETE JOIN che puoi utilizzare per rimuovere rapidamente le righe duplicate.

La seguente istruzione elimina le righe duplicate e mantiene l'id più alto:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;

5

Ho trovato un modo semplice. (mantieni l'ultimo)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;

4

Semplice e veloce per tutti i casi:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);

Codice errore: 1055. L'espressione n. 2 dell'elenco SELECT non è nella clausola GROUP BY e contiene la colonna non aggregata 'dub.id' che non dipende funzionalmente dalle colonne nella clausola GROUP BY; questo è incompatibile con sql_mode = only_full_group_by
Swoogan,

si potrebbe disattivare il "controllo duro" con sql_mode, vedi stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz

4

Ciò eliminerà le righe duplicate con gli stessi valori per titolo, azienda e sito. La prima occorrenza verrà mantenuta e tutti i duplicati verranno eliminati

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;

è lento (5w + righe, timeout attesa blocco) ma ha funzionato
yurenchen

3

Continuo a visitare questa pagina ogni volta che google "rimuovi i duplicati dal modulo mysql" ma per quanto mi riguarda le soluzioni theIGNORE non funzionano perché ho una tabella mysql InnoDB

questo codice funziona sempre meglio

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = il nome della tabella che devi pulire

tableToclean_temp = una tabella temporanea creata ed eliminata


2

Questa soluzione sposterà i duplicati in una tabella e gli unici in un'altra .

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs

Perché hai preso il sindacato e non solo SELECT * FROM jobs GROUP BY site_id, company, title, location?
timctran,

2

A partire dalla versione 8.0 (2018), MySQL supporta finalmente le funzioni della finestra .

Le funzioni della finestra sono sia utili che efficienti. Ecco una soluzione che dimostra come usarli per risolvere questo compito.

In una sottoquery, possiamo usare ROW_NUMBER()per assegnare una posizione a ciascun record nella tabella all'interno di column1/column2gruppi, ordinati per id. Se non ci sono duplicati, il record otterrà il numero di riga 1. Se esiste un duplicato, saranno numerati in ordine crescente id(a partire da1 ).

Una volta che i record sono correttamente numerati nella sottoquery, la query esterna elimina tutti i record il cui numero di riga non è 1.

Query:

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)

1

Per eliminare il record duplicato in una tabella.

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

o

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);

1
-- Here is what I used, and it works:
create table temp_table like my_table;
-- t_id is my unique column
insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;

0

Per duplicare i record con colonne univoche, ad esempio COL1, COL2, COL3 non devono essere replicati (supponiamo che abbiamo perso 3 colonne univoche nella struttura della tabella e che siano state create più voci duplicate nella tabella)

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

La speranza aiuterà dev.


0

TL; TR;

Un tutorial molto descritto per risolvere questo problema è disponibile sul sito mysqltutorial.org :

Come eliminare le righe duplicate in MySQL

Viene mostrato molto chiaramente come eliminare le righe duplicate in tre modi diversi :

A) Utilizzo DELETE JOINdell'istruzione

B) Utilizzo di una tabella intermedia

C) Utilizzo della ROW_NUMBER()funzione

Spero che possa aiutare qualcuno.


0

Ho una tabella che dimentica di aggiungere una chiave primaria nella riga ID. Anche se is ha auto_increment sull'id. Ma un giorno, una cosa riproduce il registro bin mysql sul database che inserisce alcune righe duplicate.

Rimuovo la riga duplicata di

  1. seleziona le righe duplicate univoche ed esportale

select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c > 1 group by T1.id;

  1. elimina le righe duplicate per ID

  2. inserire la riga dai dati esportati.

  3. Quindi aggiungere la chiave primaria su ID


-2

Mi piace essere un po 'più specifico su quali record elimino, quindi ecco la mia soluzione:

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)

-4

Puoi facilmente eliminare i record duplicati da questo codice.

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))
{
$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1){
    while($row = mysql_fetch_array($qry2)){
        $city_arry[] = $row;

        }

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++){


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            }
    }
    //exit;
}

3
Questa è una pessima forma - le attività del database dovrebbero essere eseguite nel DB, dove sono molto più veloci, invece di inviare dati costantemente tra php / mysql perché ne conosci uno meglio dell'altro.
Max

-4

Ho dovuto farlo con i campi di testo e ho riscontrato il limite di 100 byte sull'indice.

Ho risolto questo aggiungendo una colonna, facendo un hash md5 dei campi e facendo l'alterazione.

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.