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 |