Mysql
 sql >> Datenbank >  >> RDS >> Mysql

7 Möglichkeiten, doppelte Zeilen zu finden, während der Primärschlüssel in MySQL ignoriert wird

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