Se si dispone di due record DIFFERENTI con la stessa colonna Prodotto, è possibile selezionare i record indesiderati con alcuni criteri, ad es.
CREATE TABLE victims AS
SELECT MAX(entryDate) AS date, Product, COUNT(*) AS dups FROM ProductsTable WHERE ...
GROUP BY Product HAVING dups > 1;
Quindi è possibile eseguire un ELIMINA UNISCI tra ProductTable e Victims.
Oppure selezionare Solo prodotto, quindi eseguire un CANC per alcune altre condizioni JOIN, ad esempio con CustomerId non valido o EntryDate NULL o altro. Questo funziona se si specifica che conosce che esiste una sola copia valida del Prodotto e che tutti gli altri sono riconoscibili dai dati non validi.
Supponiamo che tu abbia documenti IDENTICI (o che tu abbia entrambi identici e non identici, oppure potresti avere diversi duplicati per qualche prodotto e non sai quale). Esegui esattamente la stessa query. Quindi, si esegue una query SELECT su ProductsTable e SELECT DISTINCT tutti i prodotti corrispondenti ai codici prodotto da deduplicare, raggruppati per prodotto e scegliendo una funzione aggregata adeguata per tutti i campi (se identico, qualsiasi aggregato dovrebbe fare. o MIN).Ciò "salverà" esattamente una riga per ogni prodotto.
A quel punto si esegue il comando DELETE JOIN e si eliminano tutti i prodotti duplicati. Quindi, reimportare semplicemente il sottoinsieme salvato e deduplicato nella tabella principale.
Ovviamente, tra il DELETE JOIN e l'INSERT SELECT, si avrà il DB in uno stato instabile, con tutti i prodotti con almeno un duplicato semplicemente scomparso.
Un altro modo che dovrebbe funzionare in MySQL:
-- Create an empty table
CREATE TABLE deduped AS SELECT * FROM ProductsTable WHERE false;
CREATE UNIQUE INDEX deduped_ndx ON deduped(Product);
-- DROP duplicate rows, Joe the Butcher's way
INSERT IGNORE INTO deduped SELECT * FROM ProductsTable;
ALTER TABLE ProductsTable RENAME TO ProductsBackup;
ALTER TABLE deduped RENAME TO ProductsTable;
-- TODO: Copy all indexes from ProductsTable on deduped.
NOTA: il modo sopra NON FUNZIONA se si vuole distinguere i "buoni" e "record duplicati non validi". Funziona solo se hai ridondanti record DUPLICATE o se non ti interessa la riga che tieni e che butti via!!
EDIT: Si dice che "duplicati" hanno campi non validi. In questo caso è possibile modificare quanto sopra con un trucco di smistamento:
SELECT * FROM ProductsTable ORDER BY Product, FieldWhichShouldNotBeNULL IS NULL;
Poi, se si dispone di una sola riga per il prodotto, cosa buona e giusta, otterrà selezionato. Se ne hai di più, quello per cui (FieldWhichShouldNeverBeNull IS NULL) è FALSE (cioè quello in cui FieldWhichShouldNeverBeNull non è effettivamente nullo come dovrebbe) verrà selezionato per primo e inserito. Tutti gli altri rimbalzeranno, silenziosamente a causa della clausola IGNORE, contro l'unicità del Prodotto. Non è un modo molto carino per farlo (e verificare che non ho mescolato true con false nella mia clausola!), Ma dovrebbe funzionare.
EDIT
in realtà più di una nuova risposta
Si tratta di una semplice tabella per illustrare il problema
CREATE TABLE ProductTable (Product varchar(10), Description varchar(10));
INSERT INTO ProductTable VALUES ('CBPD10', 'C-Beam Prj');
INSERT INTO ProductTable VALUES ('CBPD11', 'C Proj Mk2');
INSERT INTO ProductTable VALUES ('CBPD12', 'C Proj Mk3');
Non ci sono indice, e nessuna chiave primaria. Potremmo ancora dichiarare il prodotto come chiave primaria.
Ma succede qualcosa di brutto. Entrano due nuovi record e entrambi hanno una descrizione NULL.
Tuttavia, il secondo è un prodotto valido poiché non sapevamo nulla di CBPD14 prima d'ora, e quindi NON vogliamo perdere completamente questo record. Noi do vogliamo sbarazzarci dello spurio CBPD10 però.
INSERT INTO ProductTable VALUES ('CBPD10', NULL);
INSERT INTO ProductTable VALUES ('CBPD14', NULL);
Un maleducato DELETE FROM WHERE ProductTable Descrizione IS NULL è fuori questione, che avrebbe ucciso CBPD14 che non è un duplicato.
Quindi lo facciamo così. In primo luogo ottenere l'elenco dei duplicati:
SELECT Product, COUNT(*) AS Dups FROM ProductTable GROUP BY Product HAVING Dups > 1;
Partiamo dal presupposto che: "Non v'è almeno un buon record per ogni serie di record di cattivo".
Controlliamo questa ipotesi postulando il contrario e interrogandoci. Se tutto è copacetico, ci aspettiamo che questa query non restituisca nulla.
SELECT Dups.Product FROM ProductTable
RIGHT JOIN (SELECT Product, COUNT(*) AS Dups FROM ProductTable GROUP BY Product HAVING Dups > 1) AS Dups
ON (ProductTable.Product = Dups.Product
AND ProductTable.Description IS NOT NULL)
WHERE ProductTable.Description IS NULL;
Per ulteriori verifiche, inserisco due record che rappresentano questa modalità di errore; ora mi aspetto la query sopra per restituire il nuovo codice.
INSERT INTO ProductTable VALUES ("AC5", NULL), ("AC5", NULL);
Ora la query "check" restituisce infatti,
AC5
Così, la generazione di Dups sembra buono.
Procedere ora per eliminare tutti i record duplicati che non sono validi. Se ci sono duplicati, record validi, rimarranno duplicati a meno che non si trovi qualche condizione, distinguendo tra loro un record "buono" e dichiarando tutti gli altri "non validi" (magari ripetendo la procedura con un campo diverso da Descrizione).
Ma sì, c'è un problema. Attualmente, non è possibile eliminare da una tabella e selezionare dalla stessa tabella in una sottoquery (http://dev.mysql.com/doc/refman/5.0/en/delete.html). È quindi necessaria una piccola soluzione:
CREATE TEMPORARY TABLE Dups AS
SELECT Product, COUNT(*) AS Duplicates
FROM ProductTable GROUP BY Product HAVING Duplicates > 1;
DELETE ProductTable FROM ProductTable JOIN Dups USING (Product)
WHERE Description IS NULL;
Ora questo cancellerà tutti i record non validi, purché compaiano nella tabella Dups.
Pertanto, il nostro record CBPD14 non verrà toccato, perché non appare lì. Il record "buono" per CBPD10 rimarrà invariato perché non è vero che la sua Descrizione sia NULL. Tutti gli altri - puf.
Let me stato ancora una volta che se un record ha non record validi e ancoraè un duplicato, poi tutte le copie di quel disco verranno uccisi - non ci saranno superstiti.
Per evitare questo, è possibile innanzitutto selezionare (utilizzando la query sopra, il controllo "che non deve restituire nulla") le righe che rappresentano questa modalità di errore in un'altra TABELLA TEMPORANEA, quindi INSERIRLE nuovamente nella tabella principale dopo l'eliminazione (utilizzando le transazioni potrebbe essere in ordine).
Quanto è grande il database. Stiamo parlando di milioni di righe qui? Miliardi? –
circa 200.000 record con 3000 duplicati, non molto: D – Sypress
Quando si hanno due record con gli stessi dati per Prodotto, ma dati diversi in altre colonne, come si fa a sapere qual è quello corretto da conservare? –