Як знайти дублікати в 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
Одним із способів було б схопити всі чіткі дані та відтворити таблицю.
Мідегі Кодер

1
@John Isaacks: Якщо немає інших полів, з якими ви могли б їх розрізнити (тобто всі поля є дублікатами), вам доведеться видалити обидва рядки та відтворити одне. Одним із способів було б скопіювати дублікати в копію таблиці, видалити їх з оригіналу та знову вставити окремі рядки з копії.
П тато

Це не працює на postgres 8.1, хтось може мені в цьому допомогти?
Леннон

велике спасибі, чи є порядок, який ви групуєте за матерією?
Андрій

35

Мені здалося корисним додати індекс 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а потім наведена вище команда спрацює нормально

Оновлення - 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
Щоправда, але принаймні для наступного разу ти знаєш. У мене було те саме питання, і я вважав, що добре поділитися з іншими
SeanDowney

Я лише дражнила, що вона запізнюється на 3 роки. Дійсно рада, що ви поділилися. Звідси плюс 1.
JD Isaacks

Я думаю, що це видаляє один з дублікатів довільно, тому переконайтеся, що між різними рядками немає різних даних, які можуть бути корисними для знань чи збереження.
Джошуа Пінтер

+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.)


1
Я думаю, що це працює, але він не дозволить мені це робити, поки спочатку я не видалю копії. Дякую.
JD Isaacks

1

ця публікація ТА допомогла мені, але я теж хотів знати, як видалити та зберегти один із рядків ... ось рішення 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.