Oracle
 sql >> Datenbank >  >> RDS >> Oracle

11 Möglichkeiten, doppelte Zeilen zu finden, die einen Primärschlüssel in Oracle haben

Hier sind elf Optionen zum Zurückgeben doppelter Zeilen in Oracle Database, wenn diese Zeilen einen Primärschlüssel oder eine andere eindeutige Kennungsspalte haben und Sie sie ignorieren möchten.

Beispieldaten

Wir verwenden die folgenden Daten für unsere Beispiele:

SELECT * FROM Dogs;

Ergebnis:

HUNDID VORNAME NACHNAME
1 Rillen Smith
2 Rillen Smith
3 Wuff Jones
4 Ruff Robinson
5 Wag Johnson
6 Wag Johnson
7 Wag Johnson

Die ersten beiden Zeilen sind Duplikate und die letzten drei Zeilen sind Duplikate. Die doppelten Zeilen teilen genau die gleichen Werte in allen Spalten mit Ausnahme ihrer Primärschlüssel-/eindeutigen ID-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. Aber die Tatsache, dass Primärschlüssel eindeutige Werte enthalten, bedeutet, dass wir diese Spalte bei der Suche nach Duplikaten ignorieren müssen.

In unserer obigen Tabelle ist die Primärschlüsselspalte eine aufsteigende Zahl, und ihr Wert hat keine Bedeutung und ist nicht signifikant. Wir können daher die Daten dieser Spalte bei der Suche nach Duplikaten ignorieren.

Option 1

Hier ist unsere erste Option zum Zurückgeben von Duplikaten:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;

Ergebnis:

VORNAME NACHNAME COUNT
Wag Johnson 3
Barke Smith 2
Ruff Robinson 1
Wuff Jones 1

Hier haben wir unsere Abfrage mit dem GROUP BY konstruiert -Klausel, sodass die Ausgabe nach den relevanten Spalten gruppiert wird. Wir haben auch den COUNT() verwendet Funktion, um die Anzahl der identischen Zeilen zurückzugeben. Und wir haben es nach Anzahl in absteigender Reihenfolge sortiert, sodass die Duplikate zuerst angezeigt werden.

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

Wir können das HAVING hinzufügen -Klausel zu unserem vorherigen Beispiel, um Nicht-Duplikate von der Ausgabe auszuschließen:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC;

Ergebnis:

VORNAME NACHNAME COUNT
Wag Johnson 3
Barke Smith 2

Option 3

Wir können auch nach Duplikaten in verketteten Spalten suchen. In diesem Fall verwenden wir den DISTINCT Schlüsselwort, um unterschiedliche Werte zu erhalten, und verwenden Sie dann COUNT() Funktion, um die Zählung zurückzugeben:

SELECT
    DISTINCT FirstName || ' ' || LastName AS DogName,
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC;

Ergebnis:

HUNDENAME COUNT
Wag Johnson 3
Bark Smith 2
Ruff Robinson 1
Woof Jones 1

Option 4

Jede Zeile in Oracle hat eine rowid Pseudospalte, die die Adresse der Zeile zurückgibt. Die rowid ist ein eindeutiger Bezeichner für Zeilen in der Tabelle, und normalerweise identifiziert sein Wert eine Zeile in der Datenbank eindeutig (obwohl es wichtig ist zu beachten, dass Zeilen in verschiedenen Tabellen, die zusammen im selben Cluster gespeichert sind, dieselbe rowid ).

Wie auch immer, wir können eine Abfrage konstruieren, die die rowid verwendet wenn wir wollen:

SELECT * FROM Dogs
WHERE EXISTS (
  SELECT 1 FROM Dogs d2 
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
  AND Dogs.rowid > d2.rowid
);

Ergebnis:

HUNDID VORNAME NACHNAME
2 Rillen Smith
6 Wag Johnson
7 Wag Johnson

Wir könnten SELECT * ersetzen mit DELETE um eine Deduplizierungsoperation auf der Tabelle durchzuführen.

Beachten Sie, dass wir die DogId hätten verwenden können Spalte (unser Primärschlüssel) anstelle der rowid wenn wir wollten. Das heißt, die rowid kann nützlich sein, wenn Sie die Primärschlüsselspalte aus irgendeinem Grund nicht verwenden können oder wenn die Tabelle keinen Primärschlüssel hat.

Option 5

Hier ist eine weitere Abfrage, die die rowid verwendet :

SELECT * FROM Dogs
WHERE rowid > (
  SELECT MIN(rowid) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Ergebnis:

HUNDID VORNAME NACHNAME
2 Rillen Smith
6 Wag Johnson
7 Wag Johnson

Wie im vorherigen Beispiel könnten wir den SELECT * ersetzen mit DELETE um die doppelten Zeilen zu löschen.

Option 6

Die beiden rowid Die obigen Optionen sind großartig, wenn Sie den Primärschlüssel in Ihrer Abfrage vollständig ignorieren müssen (oder wenn Sie überhaupt keine Primärschlüsselspalte haben). Wie bereits erwähnt, besteht jedoch immer noch die Möglichkeit, rowid zu ersetzen mit der Primärschlüsselspalte – in unserem Fall die DogId Spalte:

SELECT * FROM Dogs
WHERE EXISTS (
  SELECT 1 FROM Dogs d2 
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
  AND Dogs.DogId > d2.DogId
);

Ergebnis:

HUNDID VORNAME NACHNAME
2 Rillen Smith
6 Wag Johnson
7 Wag Johnson

Option 7

Und hier ist die andere Abfrage mit der rowid durch die DogId ersetzt Spalte:

SELECT * FROM Dogs
WHERE DogId > (
  SELECT MIN(DogId) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Ergebnis:

HUNDID VORNAME NACHNAME
2 Rillen Smith
6 Wag Johnson
7 Wag Johnson

Option 8

Eine andere Möglichkeit, Duplikate zu finden, ist die Verwendung von ROW_NUMBER() Fensterfunktion:

SELECT 
    DogId,
    FirstName,
    LastName,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS row_num
FROM Dogs;

Ergebnis:

HUNDID VORNAME NACHNAME ZEILE_NUM
1 Rillen Smith 1
2 Rillen Smith 2
4 Ruff Robinson 1
7 Wag Johnson 1
5 Wag Johnson 2
6 Wag Johnson 3
3 Wuff 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 9

Wir können das vorherige Beispiel auch als allgemeinen Tabellenausdruck in einer größeren Abfrage verwenden:

WITH cte AS 
    (
        SELECT 
            DogId,
            FirstName,
            LastName,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS row_num
        FROM Dogs
    )
SELECT * FROM cte WHERE row_num <> 1;

Ergebnis:

HUNDID VORNAME NACHNAME ZEILE_NUM
2 Rillen Smith 2
5 Wag Johnson 2
6 Wag Johnson 3

Diese Abfrage schließt Nicht-Duplikate aus der Ausgabe aus und schließt eine Zeile jedes Duplikats aus der Ausgabe aus.

Option 10

Hier ist eine andere Möglichkeit, dieselbe Ausgabe wie im vorherigen Beispiel zu erhalten:

SELECT * FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    MINUS SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Ergebnis:

HUNDID VORNAME NACHNAME
2 Rillen Smith
6 Wag Johnson
7 Wag Johnson

Dieses Beispiel verwendet Oracles MINUS -Operator, der nur eindeutige Zeilen zurückgibt, die von der ersten Abfrage zurückgegeben werden, nicht aber von der zweiten.

Das MINUS Der Operator ähnelt dem EXCEPT Operator in anderen DBMSs wie SQL Server, MariaDB, PostgreSQL und SQLite.

Option 11

Hier ist noch eine weitere Option, um Duplikate aus unserer Tabelle auszuwählen:

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:

HUNDID VORNAME NACHNAME HUNDID VORNAME NACHNAME
2 Rillen Smith 1 Rillen Smith
7 Wag Johnson 5 Wag Johnson
7 Wag Johnson 6 Wag Johnson