Doppelte Werte in MySQL finden

769

Ich habe eine Tabelle mit einer Varchar-Spalte und möchte alle Datensätze mit doppelten Werten in dieser Spalte finden. Was ist die beste Abfrage, mit der ich die Duplikate finden kann?

Jon Tackabury
quelle
1
Da Sie erwähnt haben, dass Sie alle Datensätze finden, gehe ich davon aus, dass Sie die SCHLÜSSEL sowie die duplizierten WERTE in dieser varchar-Spalte kennen müssen.
TechTravelThink
Ich kann die Schlüssel leicht genug finden, nachdem ich die Werte erhalten habe. Ich möchte wirklich nur eine Liste aller doppelten Werte.
Jon Tackabury

Antworten:

1522

Mach ein SELECTmit einer GROUP BYKlausel. Angenommen, Name ist die Spalte, in der Sie Duplikate finden möchten:

SELECT name, COUNT(*) c FROM table GROUP BY name HAVING c > 1;

Dies gibt ein Ergebnis mit dem Namenswert in der ersten Spalte und einer Zählung zurück, wie oft dieser Wert in der zweiten Spalte angezeigt wird.

Levik
quelle
27
Aber wie ist das nützlich, wenn Sie die IDs der Zeilen mit doppelten Werten nicht erhalten können? Ja, Sie können für jeden doppelten Wert eine neue Abfrage durchführen. Ist es jedoch möglich, die doppelten Werte einfach aufzulisten?
NobleUplift
23
@NobleUplift Sie können eine ausführen GROUP_CONCAT(id)und es werden die IDs aufgelistet . Siehe meine Antwort für ein Beispiel.
Matt Rardon
5
Was würde es bedeuten, wenn es heißt ERROR: column "c" does not exist LINE 1?
Benutzer
15
Ich bin verwirrt, warum dies die akzeptierte Antwort ist und warum es so viele positive Stimmen gibt. Das OP fragte: "Ich möchte alle Datensätze mit doppelten Werten in dieser Spalte finden." Diese Antwort gibt eine Zählungstabelle zurück. -1
Monica Heddneck
4
Für diejenigen, die nicht verstehen, wie HAVING funktioniert - es ist einfach ein Filter für die Ergebnismenge, also geschieht dies nach der Hauptabfrage.
John Hunt
236
SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING COUNT(*) > 1;
maxyfc
quelle
10
Überlegen gegenüber der Antwort von @ levik, da keine zusätzliche Spalte hinzugefügt wird. Macht es nützlich für die Verwendung mit IN()/ NOT IN().
Wmassingham
172
SELECT  *
FROM    mytable mto
WHERE   EXISTS
        (
        SELECT  1
        FROM    mytable mti
        WHERE   mti.varchar_column = mto.varchar_column
        LIMIT 1, 1
        )

Diese Abfrage gibt vollständige Datensätze zurück, nicht nur eindeutige varchar_column.

Diese Abfrage wird nicht verwendet COUNT(*). Wenn es viele Duplikate gibt, COUNT(*)teuer ist und Sie nicht das Ganze benötigen COUNT(*), müssen Sie nur wissen, ob es zwei Zeilen mit demselben Wert gibt.

Wenn Sie einen Index für haben, varchar_columnwird diese Abfrage natürlich erheblich beschleunigt.

Quassnoi
quelle
3
Sehr gut. Ich ORDER BY varchar_column DESChabe am Ende der Abfrage hinzugefügt .
Trante
8
Dies sollte die akzeptierte Antwort, wie sein GROUP BYund HAVINGgibt nur eine der möglichen Duplikate. Außerdem Leistung mit indiziertem Feld anstelle von COUNT(*)und die Möglichkeit, ORDER BYdoppelte Datensätze zu gruppieren.
Rémi Breton
1
Wie in den obigen Kommentaren angegeben, können Sie mit dieser Abfrage alle doppelten Zeilen auflisten. Sehr hilfreich.
TryHarder
4
Wenn ich das betrachte, verstehe ich nicht, wie es überhaupt funktionieren würde. Wird die innere Bedingung nicht immer zutreffen, da jede Zeile in der äußeren Tabelle auch in der inneren Tabelle verfügbar ist und daher jede Zeile immer mindestens mit sich selbst übereinstimmt? Ich habe die Abfrage ausprobiert und das von mir vermutete Ergebnis erhalten - jede Zeile wurde zurückgegeben. Aber bei so vielen positiven Stimmen bezweifle ich mich. Fehlt der inneren Abfrage nicht etwas wie "AND mto.id <> mti.id"? Es funktioniert für mich, wenn ich das hinzufüge.
Clox
2
@ Quassnoi In Ordnung. Ich habe versucht, es auf sqlfiddle zu stellen, aber ich habe aufgegeben, da jede Abfrage, die ich ausführen möchte, abgesehen vom Erstellen des Schemas eine Zeitüberschreitung aufweist. Ich habe herausgefunden, dass das Entfernen von "EXISTS" auch dazu führt, dass die Abfrage für mich korrekt funktioniert.
Clox
144

Aufbauend auf der Antwort von levik, um die IDs der doppelten Zeilen zu erhalten, können Sie eine ausführen, GROUP_CONCATwenn Ihr Server dies unterstützt (dies gibt eine durch Kommas getrennte Liste von IDs zurück).

SELECT GROUP_CONCAT(id), name, COUNT(*) c FROM documents GROUP BY name HAVING c > 1;
Matt Rardon
quelle
12
Die ganze Zeit ohne etwas über GROUP_CONCAT () zu wissen! sehr sehr nützlich.
Aesede
Wirklich geschätzt Matt. Das ist wirklich hilfreich! Für diejenigen, die versuchen, in phpmyadmin zu aktualisieren, wenn Sie die ID zusammen mit der folgenden Funktion belassen: Sie aktiviert SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]die Inline-Bearbeitung und sollte alle beteiligten Zeilen aktualisieren (oder zumindest die erste übereinstimmende), aber leider erzeugt die Bearbeitung einen Javascript-Fehler. ..
Armfoot
Wie würden Sie dann berechnen, wie viele IDs dupliziert werden?
CMCDragonkai
2
Wie bekomme ich nicht alle IDs gruppiert, sondern von Anfang bis Ende aufgelistet? mit all ihren jeweiligen Werten in den Spalten neben ihnen? Anstatt es zu gruppieren, werden nur ID 1 und sein Wert, ID 2 und sein Wert angezeigt. AUCH wenn die Werte für die ID gleich sind.
MailBlade
1
Sehr hilfreiche Antwort, dies sollte top sein, damit mehr Leute es sehen. Ich erinnere mich, wie viel Schmerz ich durch das Erstellen solcher Listen hatte, und es war die ganze Zeit als Befehl verfügbar.
John
13

Angenommen, Ihre Tabelle heißt TableABC und die gewünschte Spalte ist Col und der Primärschlüssel für T1 ist Key.

SELECT a.Key, b.Key, a.Col 
FROM TableABC a, TableABC b
WHERE a.Col = b.Col 
AND a.Key <> b.Key

Der Vorteil dieses Ansatzes gegenüber der obigen Antwort besteht darin, dass er den Schlüssel gibt.

TechTravelThink
quelle
4
+1 Weil es praktisch ist. Ironischerweise enthält das Ergebnis selbst Duplikate (es listet a und b, dann b und a auf)
Fabien Snauwaert
2
@ FabienSnauwaert Sie können einige der Duplikate entfernen, indem Sie weniger als (oder mehr als) vergleichen
Michael
@TechTravelThink Ihre Antwort ist sehr klar, danke dafür, aber bei einer großen Tabelle dauert es einige Zeit (ca. 2 Minuten bei mehr als 20'000 Einträgen) und nach 25 ersten Ergebnissen, wenn ich auf die nächste klicke, zeigt phpmyadmin den Fehler "# 1052 - Spalte 'id' in der
Bestellklausel
12
SELECT * 
FROM `dps` 
WHERE pid IN (SELECT pid FROM `dps` GROUP BY pid HAVING COUNT(pid)>1)
strustam
quelle
1
Nein, denn dies ist wahrscheinlich das langsamste von allen. Unterauswahlen sind notorisch langsam, da sie für jede zurückgegebene Zeile ausgeführt werden.
Oddman
10

Um herauszufinden, wie viele Datensätze in der Namensspalte des Mitarbeiters doppelt vorhanden sind, ist die folgende Abfrage hilfreich.

Select name from employee group by name having count(*)>1;
user5599549
quelle
10

Um alle Daten zu erhalten, die Duplikate enthalten, habe ich Folgendes verwendet:

SELECT * FROM TableName INNER JOIN(
  SELECT DupliactedData FROM TableName GROUP BY DupliactedData HAVING COUNT(DupliactedData) > 1 order by DupliactedData)
  temp ON TableName.DupliactedData = temp.DupliactedData;

TableName = die Tabelle, mit der Sie arbeiten.

DupliactedData = die duplizierten Daten, nach denen Sie suchen.

udi
quelle
Dieser zeigt jedes Duplikat in einer eigenen Zeile. Das ist was ich brauche. Vielen Dank.
warmwhisky
8

Meine letzte Abfrage enthielt einige der Antworten, die hier geholfen haben - das Kombinieren von Gruppieren nach, Zählen & GROUP_CONCAT.

SELECT GROUP_CONCAT(id), `magento_simple`, COUNT(*) c 
FROM product_variant 
GROUP BY `magento_simple` HAVING c > 1;

Dies gibt die ID beider Beispiele (durch Kommas getrennt), den von mir benötigten Barcode und die Anzahl der Duplikate an.

Ändern Sie Tabelle und Spalten entsprechend.

Jonathan
quelle
8

Ich sehe keine JOIN-Ansätze, die in Bezug auf Duplikate viele Verwendungszwecke haben.

Dieser Ansatz liefert Ihnen tatsächlich doppelte Ergebnisse.

SELECT t1.* FROM my_table as t1 
LEFT JOIN my_table as t2 
ON t1.name=t2.name and t1.id!=t2.id 
WHERE t2.id IS NOT NULL 
ORDER BY t1.name
Adam Fischer
quelle
2
Zu Ihrer Information - Sie sollten "eindeutiges Somecol .. auswählen", wenn möglicherweise mehr als ein doppelter Datensatz vorhanden ist. Andernfalls enthalten die Ergebnisse Duplikate der gefundenen doppelten Zeilen.
Drew
7
SELECT t.*,(select count(*) from city as tt
  where tt.name=t.name) as count
  FROM `city` as t
  where (
     select count(*) from city as tt
     where tt.name=t.name
  ) > 1 order by count desc

Ersetzen Sie die Stadt durch Ihren Tisch. Ersetzen Sie den Namen durch Ihren Feldnamen

Lalit Patel
quelle
7

Unter @ maxyfc der Antwort weiter, ich brauchte finden alle der Zeilen , die mit den doppelten Werten zurückgegeben wurden, so dass ich sie in bearbeiten könnte MySQL Workbench :

SELECT * FROM table
   WHERE field IN (
     SELECT field FROM table GROUP BY field HAVING count(*) > 1
   ) ORDER BY field
Absoluter Nullpunkt
quelle
6

Ich habe das obige Ergebnis gesehen und die Abfrage funktioniert einwandfrei, wenn Sie doppelte Spaltenwerte überprüfen müssen. Zum Beispiel E-Mail.

Wenn Sie jedoch mit mehr Spalten prüfen müssen und die Kombination des Ergebnisses überprüfen möchten, funktioniert diese Abfrage einwandfrei:

SELECT COUNT(CONCAT(name,email)) AS tot,
       name,
       email
FROM users
GROUP BY CONCAT(name,email)
HAVING tot>1 (This query will SHOW the USER list which ARE greater THAN 1
              AND also COUNT)
Davejal
quelle
Genau das, was gebraucht wurde! Hier meine Anfrage, 3 Felder auf Duplikate zu überprüfen:SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Kai Noack
4

Ich bevorzuge die Verwendung von Fensterfunktionen (MySQL 8.0+), um Duplikate zu finden, da ich die gesamte Zeile sehen konnte:

WITH cte AS (
  SELECT *
    ,COUNT(*) OVER(PARTITION BY col_name) AS num_of_duplicates_group
    ,ROW_NUMBER() OVER(PARTITION BY col_name ORDER BY col_name2) AS pos_in_group
  FROM table
)
SELECT *
FROM cte
WHERE num_of_duplicates_group > 1;

DB Fiddle Demo

Lukasz Szozda
quelle
3
SELECT 
    t.*,
    (SELECT COUNT(*) FROM city AS tt WHERE tt.name=t.name) AS count 
FROM `city` AS t 
WHERE 
    (SELECT count(*) FROM city AS tt WHERE tt.name=t.name) > 1 ORDER BY count DESC
Magier
quelle
1
Dieselbe Unterabfrage zweimal durchzuführen, scheint ineffizient zu sein.
NobleUplift
2
SELECT DISTINCT a.email FROM `users` a LEFT JOIN `users` b ON a.email = b.email WHERE a.id != b.id;
Pawel Furmaniak
quelle
1
Es ist erwähnenswert, dass dies unerträglich langsam ist oder möglicherweise nicht einmal beendet wird, wenn die abgefragte Spalte nicht indiziert ist. Ansonsten konnte ich ändern a.emailzu a.*und alle die IDs der Zeilen mit Duplikaten zu erhalten.
NobleUplift
@NobleUplift Worüber sprichst du?
Michael
@Michael Nun, da dies drei Jahre alt ist, kann ich nicht testen, welche Version von MySQL ich verwendet habe, aber ich habe dieselbe Abfrage in einer Datenbank versucht, in der die von mir ausgewählte Spalte keinen Index hatte, also hat es ziemlich lange gedauert ein paar Sekunden bis zum Ende. Ändern Sie es in SELECT DISTINCT a.*fast sofort gelöst.
NobleUplift
@ NobleUplift Ah ok. Ich kann verstehen, dass es langsam ist ... der Teil, über den ich mir Sorgen mache, ist "vielleicht nicht einmal fertig".
Michael
@Michael Ich erinnere mich nicht, auf welcher Tabelle in unserem System ich diese Abfrage ausführen musste, aber für diejenigen mit ein paar Millionen Datensätzen wären sie wahrscheinlich fertig, aber in einer Zeit, die so lange dauerte, dass ich es aufgab zu sehen, wann es würde tatsächlich enden.
NobleUplift
1

Um doppelte Zeilen mit mehreren Feldern zu entfernen, müssen Sie sie zuerst auf den neuen eindeutigen Schlüssel streichen, der für die einzigen unterschiedlichen Zeilen angegeben ist, und dann mit dem Befehl "group by" doppelte Zeilen mit demselben neuen eindeutigen Schlüssel entfernen:

Create TEMPORARY table tmp select concat(f1,f2) as cfs,t1.* from mytable as t1;
Create index x_tmp_cfs on tmp(cfs);
Create table unduptable select f1,f2,... from tmp group by cfs;
irshst
quelle
Kannst du auch eine Erklärung hinzufügen?
Robert
Warum nicht verwenden CREATE TEMPORARY TABLE ...? Eine kleine Erklärung Ihrer Lösung wäre großartig.
Maxhb
1

Ein sehr später Beitrag ... für den Fall, dass es jemandem hilft, auf der ganzen Linie zu warten ... Ich hatte die Aufgabe, passende Transaktionspaare (eigentlich beide Seiten von Konto-zu-Konto-Überweisungen) in einer Bank-App zu finden, um zu identifizieren, welche waren die 'von' und 'bis' für jede Transaktion zwischen Kontotransfers, so dass wir am Ende folgendes hatten:

SELECT 
    LEAST(primaryid, secondaryid) AS transactionid1,
    GREATEST(primaryid, secondaryid) AS transactionid2
FROM (
    SELECT table1.transactionid AS primaryid, 
        table2.transactionid AS secondaryid
    FROM financial_transactions table1
    INNER JOIN financial_transactions table2 
    ON table1.accountid = table2.accountid
    AND table1.transactionid <> table2.transactionid 
    AND table1.transactiondate = table2.transactiondate
    AND table1.sourceref = table2.destinationref
    AND table1.amount = (0 - table2.amount)
) AS DuplicateResultsTable
GROUP BY transactionid1
ORDER BY transactionid1;

Das Ergebnis ist, dass die DuplicateResultsTableZeilen Zeilen enthalten, die übereinstimmende (dh doppelte) Transaktionen enthalten, aber auch die gleichen Transaktions-IDs in umgekehrter Reihenfolge bereitstellen, wenn sie zum zweiten Mal mit demselben Paar übereinstimmen, sodass die äußere SELECTnach der ersten Transaktions-ID gruppiert werden kann durch die NutzungLEAST und GREATESTsicherstellen, dass die beiden Transaktions-IDs in den Ergebnissen immer in derselben Reihenfolge sind, was es sicher macht, bis GROUPzum ersten zu gehen, wodurch alle doppelten Übereinstimmungen eliminiert werden. Durchlief fast eine Million Rekorde und identifizierte mehr als 12.000 Spiele in knapp 2 Sekunden. Natürlich ist die Transaktions-ID der Primärindex, was wirklich geholfen hat.

Fortyninthnet
quelle
1
Select column_name, column_name1,column_name2, count(1) as temp from table_name group by column_name having temp > 1
Vipin Jain
quelle
1
SELECT ColumnA, COUNT( * )
FROM Table
GROUP BY ColumnA
HAVING COUNT( * ) > 1
Scott Ferguson
quelle
3
Dies ist falsch, da auch eindeutige Vorkommen gefunden werden. 0 sollte 1 sein.
Kafoso
1

Wenn Sie doppelte Verwendung entfernen möchten DISTINCT

Andernfalls verwenden Sie diese Abfrage:

SELECT users.*,COUNT(user_ID) as user FROM users GROUP BY user_name HAVING user > 1;

Hassan Latif Butt
quelle
0

Versuchen Sie es mit dieser Abfrage:

SELECT name, COUNT(*) value_count FROM company_master GROUP BY name HAVING value_count > 1;
Atul Akabari
quelle