Как найти дубликаты в 2 столбцах, а не в 1

72

У меня есть таблица базы данных MySQL с двумя столбцами, которые меня интересуют. Индивидуально они могут иметь дубликаты, но у них никогда не должно быть дубликатов ОБОИХ из них, имеющих одинаковое значение.

stone_id может иметь дубликаты, если для каждого заголовка upsharge другое значение, и наоборот. Но скажем, например, stone_id= 412 и upcharge_title= "sapphire", что комбинация должна выполняться только один раз.

Это нормально:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "ruby"

Это НЕ нормально:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "sapphire"

Есть ли запрос, который найдет дубликаты в обоих полях? И если возможно, есть ли способ установить, что моя база данных не позволяет этого?

Я использую MySQL версии 4.1.22

Теги:
duplicates

6 ответов

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

Вы должны настроить составной ключ между двумя полями. Для каждой строки потребуется уникальное значение stone_id и upcharge_title.

Что касается поиска существующих дубликатов, попробуйте это:

select   stone_id,
         upcharge_title,
         count(*)
from     your_table
group by stone_id,
         upcharge_title
having   count(*) > 1
  • 0
    Спасибо, что выбрал их. Не могли бы вы сказать мне, как удалить дубликаты (но оставьте, конечно, 1 копию) СПАСИБО!
  • 1
    Один из способов - собрать все данные и воссоздать таблицу.
Показать ещё 6 комментариев
25

Мне было полезно добавить индекс unqiue, используя "ALTER IGNORE", который удаляет дубликаты и применяет уникальные записи, которые звучат так, как вы хотели бы сделать. Таким образом, синтаксис будет выглядеть следующим образом:

ALTER IGNORE TABLE `table` ADD UNIQUE INDEX(`id`, `another_id`, `one_more_id`);

Это эффективно добавляет уникальное ограничение, означающее, что у вас никогда не будет дубликатов записей, а IGNORE удаляет существующие дубликаты.

Подробнее о eh ALTER IGNORE вы можете узнать здесь: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

Обновление: мне было сообщено @Inquisitive, что это может быть неудачно в версиях MySql > 5.5:

Не удается выполнить команду MySQL > 5.5 и в таблице InnoDB, а в Percona из-за их функция быстрого индексирования InnoDB [http://bugs.mysql.com/bug.php?id=40344]. В этом случае сначала запустите set session old_alter_table=1, а затем указанную выше команду будет отлично работать

  • 0
    +1 Только на 3 года позже ... но все же полезная информация. Благодарю.
  • 1
    Правда, но, по крайней мере, в следующий раз вы знаете. У меня была такая же проблема, и я подумал, что хорошо поделиться с другими
Показать ещё 8 комментариев
4

Чтобы найти дубликаты:

select stone_id, upcharge_title from tablename group by stone_id, upcharge_title having count(*)>1

Чтобы ограничить это в будущем, создайте составной уникальный ключ в этих двух областях.

  • 1
    Большое спасибо, подскажите, пожалуйста, как удалить все, кроме одного из дубликатов. А как мне настроить составной ключ в phpmyadmin. БЛАГОДАРЮ ВАС!!!
3

Вы можете найти дубликаты, подобные этому.

Select
    stone_id, upcharge_title, count(*)
from 
    particulartable
group by 
    stone_id, upcharge_title
having 
    count(*) > 1
  • 0
    Фантастика, спасибо.
2

Кстати, сложное уникальное ограничение в таблице помешало бы этому в первую очередь.

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(Это действительный T-SQL. Не уверен в MySQL.)

  • 0
    Я думаю, что это работает, но это не позволит мне сделать это, пока я сначала не удалю дубликаты. Благодарю.
0

эта служба SO помогла мне, но я тоже хотел знать, как удалить и сохранить одну из строк... здесь PHP-решение для удаления повторяющихся строк и сохранения одного (в моем случае было всего 2 столбца, и это находится в функции для очистки дублирующих ассоциаций категорий)

$dupes = $db->query('select *, count(*) as NUM_DUPES from PRODUCT_CATEGORY_PRODUCT group by fkPRODUCT_CATEGORY_ID, fkPRODUCT_ID having count(*) > 1');
if (!is_array($dupes))
    return true;
foreach ($dupes as $dupe) {
    $db->query('delete from PRODUCT_CATEGORY_PRODUCT where fkPRODUCT_ID = ' . $dupe['fkPRODUCT_ID'] . ' and fkPRODUCT_CATEGORY_ID = ' . $dupe['fkPRODUCT_CATEGORY_ID'] . ' limit ' . ($dupe['NUM_DUPES'] - 1);
}

(ограничение NUM_DUPES - 1) является тем, что сохраняет одну строку...

спасибо всем

  • 3
    ALTER IGNORE TABLE table ADD UNIQUE INDEX index_name(stone_id, charge_title) удалит дублирующиеся строки, оставив только одну уникальную пару.

Ещё вопросы

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