Her er elleve muligheder for at returnere duplikerede rækker i Oracle Database, når disse rækker har en primær nøgle eller en anden unik identifikatorkolonne, og du vil ignorere den.
Eksempeldata
Vi bruger følgende data til vores eksempler:
SELECT * FROM Dogs;
Resultat:
DOGID | FIRSTNAME | Efternavn |
---|---|---|
1 | Gø | Smith |
2 | Gø | Smith |
3 | Wuf | Jones |
4 | Ruff | Robinson |
5 | Wag | Johnson |
6 | Wag | Johnson |
7 | Wag | Johnson |
De første to rækker er dubletter, og de sidste tre rækker er dubletter. De dublerede rækker deler nøjagtigt de samme værdier på tværs af alle kolonner med undtagelse af deres primære nøgle/unik id-kolonne.
Primærnøglekolonnen sikrer, at der ikke er duplikerede rækker, hvilket er god praksis i RDBMS'er, fordi primærnøgler hjælper med at håndhæve dataintegritet. Men det faktum, at primærnøgler indeholder unikke værdier, betyder, at vi er nødt til at ignorere den kolonne, når vi søger efter dubletter.
I vores tabel ovenfor er den primære nøglekolonne et stigende tal, og dens værdi har ingen betydning og er ikke signifikant. Vi kan derfor ignorere den kolonnes data, når vi søger efter dubletter.
Valgmulighed 1
Her er vores første mulighed for at returnere dubletter:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;
Resultat:
FØRSTENAVN | Efternavn | COUNT |
---|---|---|
Wag | Johnson | 3 |
Gø | Smith | 2 |
Ruff | Robinson | 1 |
Wuf | Jones | 1 |
Her konstruerede vi vores forespørgsel med GROUP BY
klausul, så outputtet er grupperet efter de relevante kolonner. Vi brugte også COUNT()
funktion for at returnere antallet af identiske rækker. Og vi bestilte det efter antal i faldende rækkefølge, så dubletterne vises først.
Resultatet fortæller os, at der er tre rækker indeholdende Wag Johnson og to rækker indeholdende Bark Smith. Disse er dubletter (eller triplikater i tilfældet med Wag Johnson). De to andre rækker har ingen dubletter.
Valgmulighed 2
Vi kan tilføje HAVING
klausul til vores tidligere eksempel for at udelukke ikke-duplikater fra output:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC;
Resultat:
FØRSTENAVN | Efternavn | COUNT |
---|---|---|
Wag | Johnson | 3 |
Gø | Smith | 2 |
Valgmulighed 3
Vi kan også kontrollere for dubletter på sammenkædede kolonner. I dette tilfælde bruger vi DISTINCT
søgeord for at få forskellige værdier, og brug derefter COUNT()
funktion for at returnere antallet:
SELECT
DISTINCT FirstName || ' ' || LastName AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC;
Resultat:
DOGNAME | COUNT |
---|---|
Wag Johnson | 3 |
Bark Smith | 2 |
Ruff Robinson | 1 |
Woof Jones | 1 |
Valgmulighed 4
Hver række i Oracle har en rowid
pseudokolonne, der returnerer adressen på rækken. rovid
er en unik identifikator for rækker i tabellen, og normalt identificerer dens værdi entydigt en række i databasen (selvom det er vigtigt at bemærke, at rækker i forskellige tabeller, der er gemt sammen i den samme klynge, kan have den samme række kode> ).
Under alle omstændigheder kan vi konstruere en forespørgsel, der bruger rovid
hvis vi vil:
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
);
Resultat:
DOGID | FIRSTNAME | Efternavn |
---|---|---|
2 | Gø | Smith |
6 | Wag | Johnson |
7 | Wag | Johnson |
Vi kunne erstatte SELECT *
med DELETE
at udføre en de-duping operation på bordet.
Bemærk, at vi kunne have brugt DogId
kolonne (vores primære nøgle) i stedet for ruvid
hvis vi ville. Når det er sagt, rovid
kan være nyttigt, hvis du af en eller anden grund ikke kan bruge primærnøglekolonnen, eller hvis tabellen ikke har en primærnøgle.
Valgmulighed 5
Her er en anden forespørgsel, der bruger rovid
:
SELECT * FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Resultat:
DOGID | FIRSTNAME | Efternavn |
---|---|---|
2 | Gø | Smith |
6 | Wag | Johnson |
7 | Wag | Johnson |
Som med det foregående eksempel kunne vi erstatte SELECT *
med DELETE
for at slette de duplikerede rækker.
Valgmulighed 6
De to rovid
mulighederne ovenfor er gode, hvis du fuldstændig skal ignorere den primære nøgle i din forespørgsel (eller hvis du slet ikke har en primær nøglekolonne). Men som nævnt er der stadig mulighed for at erstatte rovid
med den primære nøglekolonne – i vores tilfælde DogId
kolonne:
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
);
Resultat:
DOGID | FIRSTNAME | Efternavn |
---|---|---|
2 | Gø | Smith |
6 | Wag | Johnson |
7 | Wag | Johnson |
Valgmulighed 7
Og her er den anden forespørgsel med rovid
erstattet af DogId
kolonne:
SELECT * FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Resultat:
DOGID | FIRSTNAME | Efternavn |
---|---|---|
2 | Gø | Smith |
6 | Wag | Johnson |
7 | Wag | Johnson |
Valgmulighed 8
En anden måde at finde dubletter på er at bruge ROW_NUMBER()
vinduesfunktion:
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs;
Resultat:
DOGID | FIRSTNAME | Efternavn | ROW_NUM |
---|---|---|---|
1 | Gø | Smith | 1 |
2 | Gø | Smith | 2 |
4 | Ruff | Robinson | 1 |
7 | Wag | Johnson | 1 |
5 | Wag | Johnson | 2 |
6 | Wag | Johnson | 3 |
3 | Wuf | Jones | 1 |
Brug af PARTITION
klausul resulterer i, at der tilføjes en ny kolonne med et rækkenummer, der stiger hver gang der er en dublet, men nulstilles igen, når der er en unik række.
I dette tilfælde grupperer vi ikke resultaterne, hvilket betyder, at vi kan se hver dubletrække, inklusive dens unikke identifikatorkolonne.
Valgmulighed 9
Vi kan også bruge det forrige eksempel som et almindeligt tabeludtryk i en større forespørgsel:
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;
Resultat:
DOGID | FIRSTNAME | Efternavn | ROW_NUM |
---|---|---|---|
2 | Gø | Smith | 2 |
5 | Wag | Johnson | 2 |
6 | Wag | Johnson | 3 |
Denne forespørgsel udelukker ikke-duplikater fra outputtet, og den ekskluderer en række af hver dublet fra outputtet.
Valgmulighed 10
Her er en anden måde at få det samme output som det foregående eksempel:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultat:
DOGID | FIRSTNAME | Efternavn |
---|---|---|
2 | Gø | Smith |
6 | Wag | Johnson |
7 | Wag | Johnson |
Dette eksempel bruger Oracles MINUS
operator, som kun returnerer unikke rækker returneret af den første forespørgsel, men ikke af den anden.
EXCEPT
operatør i andre DBMS'er, såsom SQL Server, MariaDB, PostgreSQL og SQLite.
Valgmulighed 11
Her er endnu en mulighed for at vælge dubletter fra vores tabel:
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
);
Resultat:
DOGID | FIRSTNAME | Efternavn | DOGID | FIRSTNAME | Efternavn |
---|---|---|---|---|---|
2 | Gø | Smith | 1 | Gø | Smith |
7 | Wag | Johnson | 5 | Wag | Johnson |
7 | Wag | Johnson | 6 | Wag | Johnson |