sql >> Database teknologi >  >> RDS >> Oracle

11 måder at finde dublerede rækker, der har en primær nøgle i Oracle

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 Smith
2 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
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
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 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 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 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 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 Smith 1
2 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 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 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.

MINUS operatoren ligner 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 Smith 1 Smith
7 Wag Johnson 5 Wag Johnson
7 Wag Johnson 6 Wag Johnson

  1. Klyngebekræftelsesværktøj genererer et stort antal xml-filer på "/u01" filsystem.

  2. Sådan benchmarker du Moodles ydeevne

  3. Visualisering af vendepunktet med Plan Explorer

  4. Dataingeniørinterviewspørgsmål med Python