Här är några alternativ för att ta bort dubbletter av rader från en tabell i Oracle Database när dessa rader har en primärnyckel eller unik identifierarkolumn.
I sådana fall måste primärnyckeln ignoreras när du jämför dubbletter av rader (på grund av att primärnycklar har unika värden).
Exempeldata
Våra exempel använder följande data:
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | LASTNAME |
---|---|---|
1 | Skall | Smith |
2 | Skall | Smith |
3 | Wuff | Jones |
4 | Ruff | Robinson |
5 | Wag | Johnson |
6 | Wag | Johnson |
7 | Wag | Johnson |
Vi kan se att de två första raderna är dubbletter, liksom de tre sista raderna.
DogId
kolumnen innehåller unika värden (eftersom det är tabellens primärnyckel), men vi ignorerar den kolumnen när vi jämför dubbletter. Du kanske ofta behöver dedupera tabeller som innehåller primärnycklar, och därför kan följande exempel användas för att göra just det.
Alternativ 1
Här är vårt första alternativ för att dedupera tabellen ovan:
DELETE FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | LASTNAME |
---|---|---|
1 | Skall | Smith |
3 | Wuff | Jones |
4 | Ruff | Robinson |
5 | Wag | Johnson |
Dubbletterna har tagits bort (men en rad av varje duplikat finns kvar).
Vi kan alternativt använda MAX()
funktion istället för MIN()
funktion för att ändra vilka rader som tas bort.
Alternativ 2
I det här exemplet (och följande exempel) antar vi att tabellen har återställts till sitt ursprungliga tillstånd (med dubbletter).
Här är ett annat exempel som avduperar tabellen och sedan väljer de återstående raderna:
DELETE FROM Dogs WHERE DogId IN (
SELECT d2.DogId
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
)
);
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | LASTNAME |
---|---|---|
2 | Skall | Smith |
3 | Wuff | Jones |
4 | Ruff | Robinson |
7 | Wag | Johnson |
Lägg märke till att jag använde MAX()
funktion istället för MIN()
som jag använde i föregående exempel. Vi kan se vilken inverkan detta har på de-dupingverksamheten. Den tog bort olika rader från tabellen.
Alternativ 3
Här är ett alternativ som inte kräver användning av MIN()
eller MAX()
:
DELETE FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.DogId > d2.DogId
);
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | LASTNAME |
---|---|---|
1 | Skall | Smith |
3 | Wuff | Jones |
4 | Ruff | Robinson |
5 | Wag | Johnson |
Alternativ 4
Här är ett annat alternativ:
DELETE FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | LASTNAME |
---|---|---|
1 | Skall | Smith |
3 | Wuff | Jones |
4 | Ruff | Robinson |
5 | Wag | Johnson |
Alternativ 5
Varje rad i Oracle har en rovid
pseudokolumn som returnerar adressen till raden. rovid
är en unik identifierare för rader i tabellen, och vanligtvis identifierar dess värde unikt en rad i databasen (även om det är viktigt att notera att rader i olika tabeller som lagras tillsammans i samma kluster kan ha samma radid ).
Vi kan därför använda rovid
i vår fråga istället för DogId
kolumn:
DELETE FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.rowid > d2.rowid
);
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | LASTNAME |
---|---|---|
1 | Skall | Smith |
3 | Wuff | Jones |
4 | Ruff | Robinson |
5 | Wag | Johnson |
Även om det här exemplet kan verka lite överflödigt, eftersom vi redan har en primärnyckelkolumn, kan det finnas tillfällen där du föredrar att använda rovid
. rovid
kan vara användbart om du inte kan använda primärnyckelkolumnen av någon anledning, eller om tabellen inte har en primärnyckel. Oracles dokumentation nämner också att rovid
värden är det snabbaste sättet att komma åt en enskild rad.
Alternativ 6
Och här är det andra exemplet, men med rowid
istället för primärnyckeln:
DELETE FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | LASTNAME |
---|---|---|
1 | Skall | Smith |
3 | Wuff | Jones |
4 | Ruff | Robinson |
5 | Wag | Johnson |