Удалить все дубликаты строк, кроме одного в MySQL? [Дубликат]

328

Возможный дубликат:
Удалить повторяющиеся строки в MySQL

Как удалить все повторяющиеся данные из таблицы MySQL?

Например, со следующими данными:

SELECT * FROM names;
+----+--------+
| id | name   |
+----+--------+
| 1  | google |
| 2  | yahoo  |
| 3  | msn    |
| 4  | google |
| 5  | google |
| 6  | yahoo  |
+----+--------+

Я бы использовал SELECT DISTINCT name FROM names;, если это был запрос SELECT. Как мне сделать это с помощью DELETE, чтобы удалить только дубликаты и сохранить только одну запись?

  • 37
    Дубликат stackoverflow.com/questions/3311903/… и stackoverflow.com/questions/2867530/… (как ни странно).
  • 22
    Это не совсем повторяющийся вопрос, так как здесь требуется, чтобы команда DELETE выполнила то же действие, что и команда ALTER, добавляющая уникальный индекс, для автоматического удаления MySQL дублирующихся строк. В этом случае мы выбираем, как именно мы хотим удалить дубликаты.
Показать ещё 1 комментарий
Теги:
duplicate-removal

2 ответа

717
Лучший ответ

NB - вам нужно сделать это сначала на тестовой копии таблицы!

Когда я это сделал, я обнаружил, что, если я не включил AND n1.id <> n2.id, он удалил каждую строку в таблице.

1) Если вы хотите сохранить строку с наименьшим значением id:

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

2) Если вы хотите сохранить строку с наивысшим значением id:

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

Я использовал этот метод в MySQL 5.1

Не уверен в других версиях.

Обновление: поскольку пользователи Google для удаления дубликатов заканчиваются здесь
Хотя вопрос OP о DELETE, пожалуйста, имейте в виду, что использование INSERT и DISTINCT происходит намного быстрее. Для базы данных с 8 миллионами строк запрос ниже занимает 13 минут, а при использовании DELETE прошло более 2 часов, но не завершилось.

INSERT INTO tempTableName(cellId,attributeId,entityRowId,value)
    SELECT DISTINCT cellId,attributeId,entityRowId,value
    FROM tableName;
  • 77
    Отличное решение. Это сработало отлично. Но у меня есть одно предложение: мы должны поменять условия. Вместо [WHERE n1.id> n2.id AND n1.name = n2.name] мы должны написать [WHERE n1.name = n2.name AND n1.id> n2.id], это улучшит производительность, если у нас так много данные.
  • 11
    К вашему сведению: это игнорирует строки, где столбец "имя" является нулевым.
Показать ещё 27 комментариев
149

Если вы хотите сохранить строку с самым низким значением id:

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

Если вы хотите, чтобы значение id было самым высоким:

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

Подзапрос в подзапросе необходим для MySQL, или вы получите ошибку 1093.

  • 6
    Что делает «х»?
  • 6
    @GDmac служит псевдонимом для внутреннего запроса. Если не указан, будет выдана ошибка.
Показать ещё 16 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню