PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

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

Hier sind sieben Möglichkeiten, doppelte Zeilen in PostgreSQL zurückzugeben, wenn diese Zeilen einen Primärschlüssel oder eine andere eindeutige Kennungsspalte haben.

Das bedeutet, dass die doppelten Zeilen in allen Spalten genau die gleichen Werte aufweisen, mit Ausnahme ihrer Primärschlüssel-/eindeutigen ID-Spalte.

Beispieldaten

Wir verwenden die folgenden Daten für unsere Beispiele:

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 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 sich in RDBMS bewährt hat, da Primärschlüssel dabei helfen, die Datenintegrität durchzusetzen. Da Primärschlüssel jedoch doppelte Zeilen verhindern, können sie unsere Fähigkeit beeinträchtigen, Duplikate zu finden.

In unserer obigen Tabelle ist die Primärschlüsselspalte eine aufsteigende Zahl, und ihr Wert hat keine Bedeutung und ist nicht signifikant. Wir müssen diese Zeile daher ignorieren, wenn wir Duplikate in den anderen Spalten finden wollen.

Möglichkeit 1

Wir können den SQL GROUP BY verwenden -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 
-----------+----------+-------
 Ruff      | Robinson |     1
 Wag       | Johnson  |     3
 Woof      | Jones    |     1
 Bark      | Smith    |     2

Hier haben wir die Primärschlüsselspalte ausgeschlossen, indem wir sie aus unserer Abfrage weggelassen haben.

Das Ergebnis sagt uns, dass es drei Zeilen mit Wag Johnson und zwei Zeilen mit Bark Smith 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 
-----------+----------+-------
 Wag       | Johnson  |     3
 Bark      | Smith    |     2

Möglichkeit 3

Hier ist ein Beispiel für die Suche nach Duplikaten in verketteten Spalten. In diesem Fall verwenden wir den CONCAT() 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 
---------------+-------
 Wag Johnson   |     3
 Ruff Robinson |     1
 Woof Jones    |     1
 Bark Smith    |     2

Option 4

Wir können alternativ die ROW_NUMBER() verwenden Fensterfunktion:

SELECT 
    *,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS Row_Number
FROM Dogs;

Ergebnis:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     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

Verwenden der PARTITION -Klausel führt dazu, dass eine neue Spalte hinzugefügt wird, mit einer Zeilennummer, die sich jedes Mal erhöht, wenn es ein Duplikat gibt, aber wieder zurückgesetzt wird, wenn es eine eindeutige Zeile gibt.

In diesem Fall gruppieren wir die Ergebnisse nicht, was bedeutet, dass wir jede doppelte Zeile sehen können, einschließlich ihrer eindeutigen ID-Spalte.

Option 5

Wir können das vorherige Beispiel auch 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 Row_Number
        FROM Dogs
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Ergebnis:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     2 | Bark      | Smith    |          2
     6 | Wag       | Johnson  |          2
     7 | Wag       | Johnson  |          3

Dadurch werden Nicht-Duplikate aus der Ausgabe ausgeschlossen, und es wird eine Zeile jedes Duplikats aus der Ausgabe ausgeschlossen. Mit anderen Worten, es werden nur die überschüssigen Zeilen der Duplikate angezeigt. Diese Zeilen sind die besten Kandidaten, um bei einem Deduplizierungsvorgang gelöscht zu werden.

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 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Ergebnis:

 dogid | firstname | lastname 
-------+-----------+----------
     6 | Wag       | Johnson
     2 | Bark      | Smith
     7 | Wag       | Johnson

Ein Unterschied zwischen diesem Beispiel und dem vorherigen besteht darin, dass für dieses Beispiel keine eigene separate Zeilennummer generiert werden muss.

Option 7

Hier ist noch eine weitere Option zum Zurückgeben doppelter Zeilen in Postgres:

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