Devo DELETE
duplicare le righe per il Sid specificato su una MySQL
tabella.
Come posso farlo con una query SQL?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
Qualcosa del genere, ma non so come farlo.
Devo DELETE
duplicare le righe per il Sid specificato su una MySQL
tabella.
Come posso farlo con una query SQL?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
Qualcosa del genere, ma non so come farlo.
Risposte:
questo rimuove i duplicati sul posto, senza creare una nuova tabella
ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)
nota: funziona bene solo se l'indice si adatta alla memoria
ALTER IGNORE
.
ALTER TABLE foo ENGINE MyISAM
a aggirarlo, dopo aver cambiato motore.
Supponiamo di avere una tabella employee
, con le seguenti colonne:
employee (first_name, last_name, start_date)
Per eliminare le righe con una first_name
colonna duplicata :
delete
from employee using employee,
employee e1
where employee.id > e1.id
and employee.first_name = e1.first_name
employee
contro se stesso per una corrispondenza dell'indice e un >
controllo su un indice sarà lento per le tabelle di grandi dimensioni. Non sarebbe meglio SELECT MAX(ID) FROM t GROUP BY unique
e poi JOIN
una corrispondenza esatta di ID
a MAX(ID)
?
In seguito rimuovi i duplicati per tutti i SID, non solo uno.
Con tavolo temporaneo
CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;
DROP TABLE table;
RENAME TABLE table_temp TO table;
Poiché temp_table
è stato appena creato, non ha indici. Dovrai ricrearli dopo aver rimosso i duplicati. Puoi controllare con quali indici hai la tabellaSHOW INDEXES IN table
Senza tabella temporanea:
DELETE FROM `table` WHERE id IN (
SELECT all_duplicates.id FROM (
SELECT id FROM `table` WHERE (`title`, `SID`) IN (
SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1
)
) AS all_duplicates
LEFT JOIN (
SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1
) AS grouped_duplicates
ON all_duplicates.id = grouped_duplicates.id
WHERE grouped_duplicates.id IS NULL
)
SELECT * FROM table GROUP BY title, SID;
Tutto dipende da quanto bene sai cosa stai facendo.
Crea la tabella e inserisci alcune righe:
create table penguins(foo int, bar varchar(15), baz datetime);
insert into penguins values(1, 'skipper', now());
insert into penguins values(1, 'skipper', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(4, 'rico', now());
select * from penguins;
+------+----------+---------------------+
| foo | bar | baz |
+------+----------+---------------------+
| 1 | skipper | 2014-08-25 14:21:54 |
| 1 | skipper | 2014-08-25 14:21:59 |
| 3 | kowalski | 2014-08-25 14:22:09 |
| 3 | kowalski | 2014-08-25 14:22:13 |
| 3 | kowalski | 2014-08-25 14:22:15 |
| 4 | rico | 2014-08-25 14:22:22 |
+------+----------+---------------------+
6 rows in set (0.00 sec)
Rimuovi i duplicati sul posto:
delete a
from penguins a
left join(
select max(baz) maxtimestamp, foo, bar
from penguins
group by foo, bar) b
on a.baz = maxtimestamp and
a.foo = b.foo and
a.bar = b.bar
where b.maxtimestamp IS NULL;
Query OK, 3 rows affected (0.01 sec)
select * from penguins;
+------+----------+---------------------+
| foo | bar | baz |
+------+----------+---------------------+
| 1 | skipper | 2014-08-25 14:21:59 |
| 3 | kowalski | 2014-08-25 14:22:15 |
| 4 | rico | 2014-08-25 14:22:22 |
+------+----------+---------------------+
3 rows in set (0.00 sec)
Hai finito, le righe duplicate vengono rimosse, l'ultima per data e ora viene mantenuta.
Non hai una timestamp
o una colonna di indice unica per ordinare? Stai vivendo in uno stato di degenerazione. Dovrai eseguire ulteriori passaggi per eliminare le righe duplicate.
crea la tabella dei pinguini e aggiungi alcune righe
create table penguins(foo int, bar varchar(15));
insert into penguins values(1, 'skipper');
insert into penguins values(1, 'skipper');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(4, 'rico');
select * from penguins;
# +------+----------+
# | foo | bar |
# +------+----------+
# | 1 | skipper |
# | 1 | skipper |
# | 3 | kowalski |
# | 3 | kowalski |
# | 3 | kowalski |
# | 4 | rico |
# +------+----------+
crea un clone della prima tabella e copialo al suo interno.
drop table if exists penguins_copy;
create table penguins_copy as ( SELECT foo, bar FROM penguins );
#add an autoincrementing primary key:
ALTER TABLE penguins_copy ADD moo int AUTO_INCREMENT PRIMARY KEY first;
select * from penguins_copy;
# +-----+------+----------+
# | moo | foo | bar |
# +-----+------+----------+
# | 1 | 1 | skipper |
# | 2 | 1 | skipper |
# | 3 | 3 | kowalski |
# | 4 | 3 | kowalski |
# | 5 | 3 | kowalski |
# | 6 | 4 | rico |
# +-----+------+----------+
L'aggregato massimo opera sul nuovo indice moo:
delete a from penguins_copy a left join(
select max(moo) myindex, foo, bar
from penguins_copy
group by foo, bar) b
on a.moo = b.myindex and
a.foo = b.foo and
a.bar = b.bar
where b.myindex IS NULL;
#drop the extra column on the copied table
alter table penguins_copy drop moo;
select * from penguins_copy;
#drop the first table and put the copy table back:
drop table penguins;
create table penguins select * from penguins_copy;
osservare e pulire
drop table penguins_copy;
select * from penguins;
+------+----------+
| foo | bar |
+------+----------+
| 1 | skipper |
| 3 | kowalski |
| 4 | rico |
+------+----------+
Elapsed: 1458.359 milliseconds
Che cosa sta facendo quella grande dichiarazione di eliminazione SQL?
I pinguini di tabella con alias 'a' vengono lasciati uniti su un sottoinsieme di pinguini di tabella chiamato alias 'b'. La tabella di destra "b", che è un sottoinsieme, trova il timestamp massimo [o max moo] raggruppato per colonne foo e bar. Questo è abbinato alla tabella di sinistra "a". (foo, bar, baz) a sinistra ha tutte le righe nella tabella. Il sottoinsieme di destra "b" ha un (maxtimestamp, foo, bar) che è abbinato a sinistra solo su quello che è il max.
Ogni riga che non è quella massima ha valore maxtimestamp di NULL. Filtra verso il basso su quelle righe NULL e avrai un insieme di tutte le righe raggruppate per foo e bar che non è l'ultimo timestamp baz. Elimina quelli.
Eseguire un backup della tabella prima di eseguire questo.
Impedisci che questo problema si ripeta in questa tabella:
Se riesci a far funzionare tutto questo, spegni il fuoco "fila doppia". Grande. Ora definisci una nuova chiave univoca composita sulla tua tabella (su quelle due colonne) per evitare che vengano aggiunti più duplicati.
Come un buon sistema immunitario, le righe errate non dovrebbero nemmeno essere consentite nella tabella al momento dell'inserimento. Successivamente tutti quei programmi che aggiungono duplicati trasmetteranno la loro protesta e quando li risolvi, questo problema non si ripresenta più.
ID
colonna di incremento automatico , la ON
clausola deve corrispondere solo alla ID
colonna, nient'altro.
Dopo essermi imbattuto in questo problema, su un enorme database, non sono stato completamente colpito dalle prestazioni di nessuna delle altre risposte. Voglio mantenere solo l'ultima riga duplicata ed eliminare il resto.
In un'istruzione a una query, senza una tabella temporanea, questo ha funzionato meglio per me,
DELETE e.*
FROM employee e
WHERE id IN
(SELECT id
FROM (SELECT MIN(id) as id
FROM employee e2
GROUP BY first_name, last_name
HAVING COUNT(*) > 1) x);
L'unica avvertenza è che devo eseguire la query più volte, ma nonostante ciò, ho scoperto che ha funzionato meglio per me rispetto alle altre opzioni.
Questo sembra funzionare sempre per me:
CREATE TABLE NoDupeTable LIKE DupeTable;
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;
Il che mantiene l'ID più basso su ciascuno dei duplicati e il resto dei record non duplicati.
Ho anche intrapreso le seguenti operazioni in modo che il problema dupe non si verifichi più dopo la rimozione:
CREATE TABLE NoDupeTable LIKE DupeTable;
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;
In altre parole, creo un duplicato della prima tabella, aggiungo un indice univoco sui campi di cui non voglio duplicati, e quindi faccio uno Insert IGNORE
che ha il vantaggio di non fallire normalmente come Insert
la prima volta che provasse ad aggiungere un record duplicato basato sui due campi e ignora piuttosto tali record.
Spostando avanti diventa impossibile creare record duplicati basati su questi due campi.
ORDER BY
in SELECT
per essere sicuro di quale disco effettivamente arriva al NoDupeTable
?
ORDER by ID Asc
non poteva far male, quindi modificherò la mia risposta.
Select Max(ID)
e poi Order by Max(ID)
ma tutto ciò che farebbe è invertire l'ordine dell'inserto. Per ottenere l'ID più alto richiederei credo che un join più complesso selezioni come, indipendentemente da come ordini sopra, afferrerai i valori del campo dall'ID inferiore.
MAX(ID)
o MIN(ID)
nomi di colonne invece che *
nel SELECT FROM DupeTable
pensiero, altrimenti ne otterrai uno solo a ID
caso. In effetti, molti SQL e persino MySQL rigorosi richiedono di chiamare una funzione aggregata su ogni colonna non specificata nella GROUP BY
clausola.
ID,First,Last,Notes
e record 1,Bob,Smith,NULL
e 2,Bob,Smith,Arrears
poi facendo un SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Last
, entrambi restituirebbero lo stesso record, 1, tranne con un ID diverso. Max (ID) sarebbe tornato 2,Bob,Smith,NULL
e Min (ID) sarebbe tornato 1,Bob,Smith,NULL
. Per ottenere il secondo disco con "Arrears" nelle note è necessario un join credo.
Ecco una semplice risposta:
delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated
from target_table GROUP BY field_being_repeated) b
on a.field_being_repeated = b.field_being_repeated
and a.id_field = b.id_field
where b.id_field is null;
and a.id_field = b.id
LEFT JOIN
to b
deve solo confrontare b.id
= a.id_field
assumendo che field_id
sia un ID di incremento automatico univoco. così a.field_being_repeated = b.field_being_repeated
è estraneo. (Anche b.id_field
in questa query non esiste b.id
.
Questo lavoro per me per rimuovere vecchi record:
delete from table where id in
(select min(e.id)
from (select * from table) e
group by column1, column2
having count(*) > 1
);
È possibile sostituire min (e.id) a max (e.id) per rimuovere i record più recenti.
delete p from
product p
inner join (
select max(id) as id, url from product
group by url
having count(*) > 1
) unik on unik.url = p.url and unik.id != p.id;
Trovo che la soluzione di Werner sopra sia la più conveniente perché funziona indipendentemente dalla presenza di una chiave primaria, non scherza con le tabelle, usa sql a prova di futuro, è molto comprensibile.
Come ho affermato nel mio commento, questa soluzione non è stata spiegata correttamente però. Quindi questo è mio, basato su di esso.
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.
Questa procedura rimuoverà tutti i duplicati (incl. Multipli) in una tabella, mantenendo l'ultimo duplicato. Questa è un'estensione del Recupero dell'ultimo record in ciascun gruppo
Spero che questo sia utile a qualcuno.
DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));
INSERT INTO UniqueIDs
(SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
(T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields
AND T1.ID < T2.ID)
WHERE T2.ID IS NULL);
DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);
Un altro modo semplice ... utilizzando UPDATE IGNORE:
Devi usare un indice su una o più colonne (digita indice). Crea una nuova colonna di riferimento temporaneo (non parte dell'indice). In questa colonna, contrassegni gli unici aggiornandoli con la clausola ignore. Passo dopo passo:
Aggiungi una colonna di riferimento temporanea per contrassegnare le uniche:
ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;
=> questo aggiungerà una colonna alla tua tabella.
Aggiorna la tabella, prova a contrassegnare tutto come univoco, ma ignora i possibili errori dovuti a problemi di chiave duplicati (i record verranno ignorati):
UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;
=> troverai che i tuoi record duplicati non saranno contrassegnati come unici = 'Sì', in altre parole solo uno di ogni set di record duplicati sarà contrassegnato come unico.
Elimina tutto ciò che non è unico:
DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';
=> Questo rimuoverà tutti i record duplicati.
Rilascia la colonna ...
ALTER TABLE `yourtable` DROP `unique`;
unique
colonna DEVE essere aggiunta a un vincolo univoco insieme alle colonne che sono attualmente duplicate, altrimenti l'intera cosa non funziona perché SET unique
= 'Sì' non fallirebbe mai.
unique
è una parola chiave mysql. Quindi deve avere i backtick (come già correttamente visualizzato). L'uso di un'altra parola per la colonna potrebbe essere più conveniente.
L'eliminazione dei duplicati sulle tabelle MySQL è un problema comune, che di solito comporta esigenze specifiche. Nel caso qualcuno fosse interessato, qui ( Rimuovi le righe duplicate in MySQL ) spiego come utilizzare una tabella temporanea per eliminare i duplicati MySQL in modo affidabile e veloce, valido anche per gestire le origini di big data (con esempi per diversi casi d'uso).
Ali , nel tuo caso, puoi eseguire qualcosa del genere:
-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;
-- add a unique constraint
ALTER TABLE tmp_table1 ADD UNIQUE(sid, title);
-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;
-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;
La risposta di Love @ eric, ma non sembra funzionare se hai un tavolo davvero grande (lo ottengo The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay
quando provo a eseguirlo). Quindi ho limitato la query di join a considerare solo le righe duplicate e ho finito con:
DELETE a FROM penguins a
LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo
FROM penguins
GROUP BY deviceId HAVING num > 1) b
ON a.baz != b.keepBaz
AND a.foo = b.foo
WHERE b.foo IS NOT NULL
La clausola WHERE in questo caso consente a MySQL di ignorare qualsiasi riga che non ha un duplicato e ignorerà anche se questa è la prima istanza del duplicato, quindi verranno ignorati solo i duplicati successivi. Passare MIN(baz)
a MAX(baz)
per mantenere l'ultima istanza anziché la prima.
Questo funziona per tavoli di grandi dimensioni:
CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1;
DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL;
Per eliminare le modifiche meno recenti max(id)
amin(id)
Questo qui trasformerà la colonna column_name
in una chiave primaria e nel frattempo ignorerà tutti gli errori. Quindi eliminerà le righe con un valore duplicato per column_name
.
ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);
Penso che funzionerà fondamentalmente copiando la tabella e svuotandola, quindi reinserendo solo i valori distinti, ma per favore ricontrolla prima di farlo su grandi quantità di dati.
Crea una copia carbone della tua tabella
crea una tabella temp_table come oldtablename; inserisci temp_table seleziona * da oldtablename;
Svuota la tua tabella originale
ELIMINA * da oldtablename;
Copia tutti i valori distinti dalla tabella copiata alla tabella originale
INSERISCI oldtablename SELEZIONA * dal gruppo temp_table per nome, cognome, dob
Elimina la tabella temporanea.
Elimina tabella temp_table
È necessario raggruppare in base a TUTTI i campi che si desidera mantenere distinti.
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
ecco come di solito elimino i duplicati
Potresti semplicemente usare una clausola DISTINCT per selezionare l'elenco "ripulito" (ed ecco un esempio molto semplice su come farlo).
DISTINCT
perdi qualsiasi informazione sui duplicati che potresti avere avuto in primo luogo. Puoi mostrare un modo per eliminare i duplicati utilizzandolo?
Potrebbe funzionare se li conti, quindi aggiungi un limite alla tua query di eliminazione lasciandone solo uno?
Ad esempio, se ne hai due o più, scrivi la tua query in questo modo:
DELETE FROM table WHERE SID = 1 LIMIT 1;
Ci sono solo alcuni passaggi di base per la rimozione di dati duplicati dalla tabella:
Ecco il tutorial completo: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473