Hier sind sieben Möglichkeiten, doppelte Zeilen in MySQL zurückzugeben, wenn diese Zeilen einen Primärschlüssel oder eine andere eindeutige Kennungsspalte haben.
Beispieldaten
Wir verwenden die folgenden Daten für unsere Beispiele:
DROP TABLE IF EXISTS Dogs;
CREATE TABLE Dogs (
DogId int PRIMARY KEY NOT NULL,
FirstName varchar(50),
LastName varchar(50)
);
INSERT INTO Dogs VALUES
(1, 'Bark', 'Smith'),
(2, 'Bark', 'Smith'),
(3, 'Woof', 'Jones'),
(4, 'Ruff', 'Robinson'),
(5, 'Wag', 'Johnson'),
(6, 'Wag', 'Johnson'),
(7, 'Wag', 'Johnson');
SELECT * FROM Dogs;
Ergebnis:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Die doppelten Zeilen haben in allen Spalten genau die gleichen Werte, mit Ausnahme ihrer Primärschlüssel-/eindeutigen ID-Spalte.
Die ersten beiden Zeilen sind Duplikate (mit Ausnahme der DogId
Spalte, die der Primärschlüssel der Tabelle ist und einen eindeutigen Wert für alle Zeilen enthält). Die letzten drei Zeilen sind ebenfalls Duplikate (mit Ausnahme der DogId
Spalte).
Die Primärschlüsselspalte stellt sicher, dass es keine doppelten Zeilen gibt, was normalerweise in RDBMSs eine gute Sache ist. Per Definition bedeutet dies jedoch, dass es keine Duplikate gibt. In unserem Fall ist die Primärschlüsselspalte eine aufsteigende Zahl, und ihr Wert hat keine Bedeutung und ist nicht signifikant. Daher müssen wir diese Zeile ignorieren, wenn wir Duplikate in den vorhandenen Spalten finden wollen von Bedeutung.
Option 1
Unsere erste Option ist die Verwendung von GROUP BY
-Klausel, um die Spalten nach ihren signifikanten Spalten zu gruppieren, und verwenden Sie dann COUNT()
Funktion, um die Anzahl identischer Zeilen zurückzugeben:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Ergebnis:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Wag | Johnson | 3 | +-----------+----------+-------+
Wir konnten die Primärschlüsselspalte ignorieren, indem wir sie in unserer Abfrage weggelassen haben.
Das Ergebnis sagt uns, dass es zwei Zeilen mit Bark Smith und drei Zeilen mit Wag Johnson gibt. Dies sind Duplikate (oder Triplikate im Fall von Wag Johnson). Die anderen beiden Zeilen haben keine Duplikate.
Option 2
Mit dem HAVING
können wir Nicht-Duplikate von der Ausgabe ausschließen Klausel:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Ergebnis:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Wag | Johnson | 3 | +-----------+----------+-------+
Option 3
Wir können auch nach Duplikaten in verketteten Spalten suchen. Zum Beispiel können wir den CONCAT()
verwenden Um unsere beiden Spalten zu verketten, verwenden Sie die Funktion DISTINCT
Schlüsselwort, um unterschiedliche Werte zu erhalten, und verwenden Sie dann COUNT()
Funktion, um die Zählung zurückzugeben:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Ergebnis:
+---------------+-------+ | DogName | Count | +---------------+-------+ | Bark Smith | 2 | | Woof Jones | 1 | | Ruff Robinson | 1 | | Wag Johnson | 3 | +---------------+-------+
Option 4
Wir können alternativ die ROW_NUMBER()
verwenden Funktion mit dem PARTITION BY
Klausel:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS rn
FROM Dogs;
Ergebnis:
+-------+-----------+----------+----+ | DogId | FirstName | LastName | rn | +-------+-----------+----------+----+ | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 5 | Wag | Johnson | 1 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +-------+-----------+----------+----+
Dadurch wird eine neue Spalte mit einer Zeilennummer erstellt, die sich jedes Mal erhöht, wenn es ein Duplikat gibt, aber wieder zurückgesetzt wird, wenn es eine eindeutige Zeile gibt
Diese Technik bietet einen möglichen Vorteil darin, dass wir die Ergebnisse nicht gruppieren müssen. Das bedeutet, dass wir jede doppelte Zeile sehen können, einschließlich ihrer eindeutigen ID-Spalte.
Option 5
Wir können das vorherige Beispiel als allgemeinen Tabellenausdruck in einer größeren Abfrage verwenden:
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS rn
FROM Dogs
)
SELECT * FROM cte WHERE rn <> 1;
Ergebnis:
+-------+-----------+----------+----+ | DogId | FirstName | LastName | rn | +-------+-----------+----------+----+ | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +-------+-----------+----------+----+
Diese Technik schließt Nicht-Duplikate aus der Ausgabe aus und schließt eine Zeile jedes Duplikats aus der Ausgabe aus.
Diese Abfrage kann als Vorläufer für eine Deduplizierungsoperation verwendet werden. Es kann uns zeigen, was gelöscht wird, wenn wir uns entscheiden, Duplikate zu löschen. Um die Tabelle zu deduplizieren, müssen wir lediglich das letzte SELECT *
ersetzen mit DELETE
.
Option 6
Hier ist ein kürzerer Weg, um die gleiche Ausgabe wie im vorherigen Beispiel zu erhalten:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName)
);
Ergebnis:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Bei dieser Technik müssen wir keine separate Zeilennummer mit ROW_NUMBER()
generieren wie im vorigen Beispiel.
Wir können auch SELECT *
ersetzen mit DELETE
um die Duplikate zu löschen.
Option 7
Und zum Schluss noch eine weitere Option zum Zurückgeben von Duplikaten:
SELECT *
FROM Dogs d1, Dogs d2
WHERE d1.FirstName = d2.FirstName
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId
AND d1.DogId = (
SELECT MAX(DogId)
FROM Dogs d3
WHERE d3.FirstName = d1.FirstName
AND d3.LastName = d1.LastName
);
Ergebnis:
+-------+-----------+----------+-------+-----------+----------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | +-------+-----------+----------+-------+-----------+----------+ | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +-------+-----------+----------+-------+-----------+----------+