Jak znaleźć duplikaty w 2 kolumnach, a nie 1

107

Mam tabelę bazy danych MySQL z dwiema kolumnami, które mnie interesują. Indywidualnie każdy z nich może mieć duplikaty, ale nigdy nie powinien mieć ich duplikatów o tej samej wartości.

stone_idmogą mieć duplikaty, o ile każdy upshargetytuł jest inny i na odwrót. Ale powiedzmy na przykład stone_id= 412 i upcharge_title= "szafir", ta kombinacja powinna wystąpić tylko raz.

To jest wporządku:

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

To NIE jest w porządku:

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

Czy istnieje zapytanie, które znajdzie duplikaty w obu polach? A jeśli to możliwe, czy istnieje sposób, aby moja baza danych na to nie zezwalała?

Używam MySQL w wersji 4.1.22

JD Isaacks
źródło

Odpowiedzi:

192

Powinieneś ustawić klucz złożony między dwoma polami. Będzie to wymagało unikalnego stone_id i upcharge_title dla każdego wiersza.

Jeśli chodzi o znajdowanie istniejących duplikatów, spróbuj tego:

select   stone_id,
         upcharge_title,
         count(*)
from     your_table
group by stone_id,
         upcharge_title
having   count(*) > 1
Miyagi Coder
źródło
Dziękuję, to je wybiera. Czy mógłbyś być tak miły i powiedzieć mi, jak usunąć duplikaty (ale oczywiście zostawić 1 kopię) DZIĘKUJĘ !!
JD Isaacks
2
Jednym ze sposobów byłoby pobranie wszystkich odrębnych danych i ponowne utworzenie tabeli.
Miyagi Coder
1
@John Isaacks: Jeśli nie ma innych pól, za pomocą których mógłbyś je rozróżnić (tj. Wszystkie pola są duplikatami), będziesz musiał usunąć oba wiersze i odtworzyć jeden. Jednym ze sposobów byłoby skopiowanie duplikatów do kopii tabeli, usunięcie ich z oryginału i ponowne wstawienie odrębnych wierszy z kopii.
P Daddy
To nie działa na postgres 8.1, czy ktoś mógłby mi w tym pomóc?
Lennon
wielkie dzięki, czy kolejność grupowania według treści?
Andrew
35

Uznałem, że pomocne jest dodanie niepotrzebnego indeksu przy użyciu opcji „ALTER IGNORE”, która usuwa duplikaty i wymusza unikalne nagrania, które brzmią tak, jak chciałbyś to zrobić. Zatem składnia byłaby następująca:

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

To skutecznie dodaje unikalne ograniczenie, co oznacza, że ​​nigdy nie będziesz mieć zduplikowanych rekordów, a IGNORE usuwa istniejące duplikaty.

Możesz przeczytać więcej o eh ALTER IGNORE tutaj: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

Aktualizacja: @Inquisitive poinformował mnie, że może się to nie udać w wersjach MySql> 5.5:

Nie udaje się na MySQL> 5.5 i na tabeli InnoDB oraz w Perconie z powodu ich funkcji szybkiego tworzenia indeksu w InnoDB [ http://bugs.mysql.com/bug.php?id=40344] . W takim przypadku najpierw uruchom, set session old_alter_table=1a następnie powyższe polecenie będzie działać dobrze

Aktualizacja - ALTER IGNOREusunięta w 5.7

Z dokumentów

W MySQL 5.6.17 klauzula IGNORE jest przestarzała, a jej użycie generuje ostrzeżenie. IGNORE została usunięta w MySQL 5.7.

Jeden z deweloperów MySQL podaje dwie alternatywy :

  • Pogrupuj według unikalnych pól i usuń, jak pokazano powyżej
  • Utwórz nową tabelę, dodaj unikalny indeks, użyj INSERT IGNORE, np .:
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;

Ale w zależności od wielkości stołu może to nie być praktyczne

SeanDowney
źródło
1
To prawda, ale przynajmniej następnym razem, gdy będziesz wiedział. Miałem ten sam problem i pomyślałem, że dobrze jest podzielić się z innymi
SeanDowney
Drażniłem się tylko, że spóźnia się 3 lata. Naprawdę cieszę się, że udostępniliście. Stąd plus 1.
JD Isaacks
Wyobrażam sobie, że to usuwa jeden z duplikatów w sposób arbitralny, więc upewnij się, że w każdym wierszu nie ma różnych danych, które mogą być przydatne do poznania lub zachowania.
Joshua Pinter
+1 za odpowiedź nawet po 2 latach spóźnienia. Przypadkowo usunąłem klucz złożony i to uratowało życie. Dziękuję
ivcode
Wypróbowałem kilka technik wyszukiwania duplikatów i żadna z nich nie była tak prosta i szybka. Dziękuję za udostępnienie tej metody.
Kristjan O.
8

Możesz znaleźć takie duplikaty ...

Select
    stone_id, upcharge_title, count(*)
from 
    particulartable
group by 
    stone_id, upcharge_title
having 
    count(*) > 1
Jason Punyon
źródło
4

Aby znaleźć duplikaty:

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

Aby uniknąć tego w przyszłości, utwórz złożony unikatowy klucz na tych dwóch polach.

Ian Nelson
źródło
1
Dziękuję bardzo, czy możesz mi powiedzieć, jak usunąć wszystkie duplikaty oprócz jednego. I jak skonfigurować klucz compisite w phpmyadmin. DZIĘKUJĘ CI!!!
JD Isaacks
3

Nawiasem mówiąc, złożone unikalne ograniczenie na stole zapobiegałoby temu w pierwszej kolejności.

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(To jest poprawny T-SQL. Nie mam pewności co do MySQL).

P tato
źródło
1
Myślę, że to działa, ale nie pozwoli mi to zrobić, dopóki najpierw nie usunę duplikatów. Dzięki.
JD Isaacks
1

ten post SO pomógł mi, ale ja też chciałem wiedzieć, jak usunąć i zachować jeden z wierszy ... oto rozwiązanie PHP, aby usunąć zduplikowane wiersze i zachować jeden (w moim przypadku były tylko 2 kolumny i jest w funkcja do usuwania powielonych powiązań kategorii)

$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);
}

(limit NUM_DUPES - 1) jest tym, co zachowuje pojedynczy wiersz ...

Dziękuje wszystkim

groovenectar
źródło
3
ALTER IGNORE TABLE table ADD UNIQUE INDEX index_name(stone_id, charge_title)usunie zduplikowane wiersze, pozostawiając tylko jedną unikalną parę.
dev-null-dweller