Usunąć wszystkie zduplikowane wiersze z wyjątkiem jednego w MySQL? [duplikat]

to pytanie ma już odpowiedzi tutaj : Usuń zduplikowane wiersze w MySQL (25 odpowiedzi) Zamknięte w zeszłym roku .

Jak usunąć wszystkie duplikaty danych z tabeli MySQL?

Na przykład z następującymi danymi:

SELECT * FROM names;

+----+--------+
| id | name   |
+----+--------+
| 1  | google |
| 2  | yahoo  |
| 3  | msn    |
| 4  | google |
| 5  | google |
| 6  | yahoo  |
+----+--------+

Użyłbym SELECT DISTINCT name FROM names;, gdyby to było SELECT zapytanie.

Jak mam to zrobić z DELETE aby usunąć tylko duplikaty i zachować tylko jeden zapis każdego z nich?

Author: DineshDB, 2011-01-13

2 answers

Ostrzeżenie edytora: To rozwiązanie jest nieefektywne obliczeniowo i może obniżyć połączenie dla dużej tabeli.

UWAGA-Musisz zrobić to najpierw na kopii testowej Twojej tabeli!

Kiedy to zrobiłem, odkryłem, że o ile nie uwzględniłem również AND n1.id <> n2.id, usunęło on każdy wiersz w tabeli.

  1. Jeśli chcesz zachować wiersz z najniższą wartością id :

    DELETE n1 FROM names n1, names n2 WHERE n1.id > n2.id AND n1.name = n2.name
    
  2. Jeśli chcesz zachować wiersz z najwyższą id wartością:

    DELETE n1 FROM names n1, names n2 WHERE n1.id < n2.id AND n1.name = n2.name
    

Użyłem tej metody w MySQL 5.1

Nie jestem pewien co do innych wersji.


Aktualizacja: ponieważ ludzie Googlujący do usuwania duplikatów kończą tutaj
Chociaż pytanie OP dotyczy DELETE, należy pamiętać, że używanie INSERT i DISTINCT jest znacznie szybsze. W przypadku bazy danych z 8 milionami wierszy poniższe zapytanie zajęło 13 minut, podczas korzystania z DELETE, zajęło to więcej niż 2 godziny, a jednak nie udało się ukończyć.

INSERT INTO tempTableName(cellId,attributeId,entityRowId,value)
    SELECT DISTINCT cellId,attributeId,entityRowId,value
    FROM tableName;
 974
Author: martin.masa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-15 21:09:35

Jeśli chcesz zachować wiersz z najniższą id wartością:

DELETE FROM NAMES
 WHERE id NOT IN (SELECT * 
                    FROM (SELECT MIN(n.id)
                            FROM NAMES n
                        GROUP BY n.name) x)

Jeśli chcesz, aby wartość id była najwyższa:

DELETE FROM NAMES
 WHERE id NOT IN (SELECT * 
                    FROM (SELECT MAX(n.id)
                            FROM NAMES n
                        GROUP BY n.name) x)

Subquery w subquery jest konieczne dla MySQL, lub dostaniesz błąd 1093.

 212
Author: OMG Ponies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-13 21:03:48