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

107

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

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

Хорошо:

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

Джей Ди Айзекс
источник

Ответы:

192

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

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

select   stone_id,
         upcharge_title,
         count(*)
from     your_table
group by stone_id,
         upcharge_title
having   count(*) > 1
Кодер Мияги
источник
Спасибо, что выбрали их. Не могли бы вы подсказать мне, как удалить дубликаты (но оставить, конечно, 1 копию) СПАСИБО !!
JD Isaacks
2
Один из способов - получить все отдельные данные и воссоздать таблицу.
Miyagi Coder,
1
@John Isaacks: Если нет других полей, с помощью которых вы могли бы их различить (т.е. все поля являются дубликатами), вам придется удалить обе строки и создать одну заново. Один из способов - скопировать дубликаты в копию таблицы, удалить их из оригинала и повторно вставить отдельные строки из копии.
P Daddy
Это не работает на postgres 8.1, может ли кто-нибудь помочь мне в этом?
Леннон
Большое спасибо, имеет ли значение порядок, который вы группируете?
Эндрю
35

Я счел полезным добавить индекс unqiue с помощью «ALTER IGNORE», который удаляет дубликаты и обеспечивает выполнение уникальных записей, которые звучат так, как вы хотели бы. Итак, синтаксис будет таким:

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

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

Вы можете узнать больше о 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а затем приведенная выше команда будет работать нормально

Обновление - ALTER IGNOREудалено в 5.7

Из документов

Начиная с MySQL 5.6.17, предложение IGNORE устарело, и его использование генерирует предупреждение. IGNORE удален в MySQL 5.7.

Один из разработчиков MySQL предлагает две альтернативы :

  • Сгруппируйте по уникальным полям и удалите, как показано выше
  • Создайте новую таблицу, добавьте уникальный индекс, используйте INSERT IGNORE, например:
CREATE TABLE duplicate_row_table LIKE regular_row_table;
ALTER TABLE duplicate_row_table ADD UNIQUE INDEX (id, another_id);
INSERT IGNORE INTO duplicate_row_table SELECT * FROM regular_row_table;
DROP TABLE regular_row_table;
RENAME TABLE duplicate_row_table TO regular_row_table;

Но в зависимости от размера вашего стола это может оказаться непрактичным.

Шон Дауни
источник
1
Верно, но по крайней мере, в следующий раз. У меня была такая же проблема, и я подумал, что
стоит
Я только дразнил, что это опоздание на 3 года. Действительно рад, что вы поделились. Отсюда плюс 1.
Джей Ди Айзекс
Я предполагаю, что это произвольно удаляет один из дубликатов, поэтому убедитесь, что между каждой строкой нет разных данных, которые может быть полезно знать или сохранять.
Джошуа Пинтер
+1 за ответ даже после опоздания на 2 года. Я случайно удалил составной ключ, и это спасло мне жизнь. Спасибо
ivcode
Я пробовал несколько методов поиска дубликатов, и ни один из них не был таким простым и быстрым. Спасибо, что поделились этим методом.
Кристьян О.
8

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

Select
    stone_id, upcharge_title, count(*)
from 
    particulartable
group by 
    stone_id, upcharge_title
having 
    count(*) > 1
Джейсон Пуньон
источник
4

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

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

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

Ян Нельсон
источник
1
Большое спасибо, не могли бы вы рассказать мне, как удалить все дубликаты, кроме одного. И как мне настроить составной ключ в phpmyadmin. СПАСИБО!!!
JD Isaacks
3

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

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

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

P Папа
источник
1
Я думаю, что это работает, но не позволит мне сделать это, пока я сначала не удалю дубликаты. Спасибо.
JD Isaacks
1

это сообщение 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)удалит повторяющиеся строки, оставив только одну уникальную пару.
dev-null-dweller