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

11 modi per trovare righe duplicate che hanno una chiave primaria in Oracle

Ecco undici opzioni per restituire righe duplicate in Oracle Database quando tali righe hanno una chiave primaria o qualche altra colonna di identificatore univoco e si desidera ignorarla.

Dati campione

Utilizzeremo i seguenti dati per i nostri esempi:

SELECT * FROM Dogs;

Risultato:

DOGID COGNOME COGNOME
1 Corteccia Fabio
2 Corteccia Fabio
3 Trama Jones
4 Ruff Robinson
5 Wag Johnson
6 Wag Johnson
7 Wag Johnson

Le prime due righe sono duplicate e le ultime tre righe sono duplicate. Le righe duplicate condividono esattamente gli stessi valori in tutte le colonne ad eccezione della loro chiave primaria/colonna ID univoco.

La colonna della chiave primaria garantisce che non vi siano righe duplicate, il che è una buona pratica negli RDBMS, poiché le chiavi primarie aiutano a rafforzare l'integrità dei dati. Ma il fatto che le chiavi primarie contengano valori univoci significa che dobbiamo ignorare quella colonna durante la ricerca di duplicati.

Nella nostra tabella sopra, la colonna della chiave primaria è un numero incrementale e il suo valore non ha significato e non è significativo. Possiamo quindi ignorare i dati di quella colonna durante la ricerca di duplicati.

Opzione 1

Ecco la nostra prima opzione per restituire i duplicati:

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

Risultato:

FIRSTNAME COGNOME COUNT
Schizzi Johnson 3
Corteccia Fabio 2
Ruff Robinson 1
Woof Jones 1

Qui abbiamo costruito la nostra query con GROUP BY clausola in modo che l'output sia raggruppato per le colonne pertinenti. Abbiamo anche usato COUNT() funzione per restituire il numero di righe identiche. E lo abbiamo ordinato per conteggio in ordine decrescente in modo che i duplicati appaiano per primi.

Il risultato ci dice che ci sono tre righe contenenti Wag Johnson e due righe contenenti Bark Smith. Questi sono duplicati (o triplicati nel caso di Wag Johnson). Le altre due righe non hanno duplicati.

Opzione 2

Possiamo aggiungere il HAVING clausola al nostro esempio precedente per escludere i non duplicati dall'output:

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

Risultato:

FIRSTNAME COGNOME COUNT
Schizzi Johnson 3
Corteccia Fabio 2

Opzione 3

Possiamo anche verificare la presenza di duplicati su colonne concatenate. In questo caso utilizziamo il DISTINCT parola chiave per ottenere valori distinti, quindi utilizza COUNT() funzione per restituire il conteggio:

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

Risultato:

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

Opzione 4

Ogni riga in Oracle ha un rowid pseudocolonna che restituisce l'indirizzo della riga. Il rowid è un identificatore univoco per le righe nella tabella e di solito il suo valore identifica in modo univoco una riga nel database (sebbene sia importante notare che righe in tabelle diverse che sono archiviate insieme nello stesso cluster possono avere lo stesso rowid ).

Ad ogni modo, possiamo costruire una query che utilizza il rowid se vogliamo:

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
);

Risultato:

DOGID COGNOME COGNOME
2 Corteccia Fabio
6 Wag Johnson
7 Wag Johnson

Potremmo sostituire SELECT * con DELETE per eseguire un'operazione di deduplicazione sul tavolo.

Nota che avremmo potuto usare DogId colonna (la nostra chiave primaria) invece di rowid se volessimo. Detto questo, il rowid può essere utile se per qualche motivo non puoi utilizzare la colonna della chiave primaria o se la tabella non ha una chiave primaria.

Opzione 5

Ecco un'altra query che utilizza rowid :

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

Risultato:

DOGID COGNOME COGNOME
2 Corteccia Fabio
6 Wag Johnson
7 Wag Johnson

Come nell'esempio precedente, potremmo sostituire SELECT * con DELETE per eliminare le righe duplicate.

Opzione 6

I due rowid le opzioni precedenti sono ottime se devi ignorare completamente la chiave primaria nella tua query (o se non hai affatto una colonna di chiave primaria). Tuttavia, come accennato, c'è ancora la possibilità di sostituire rowid con la colonna della chiave primaria, nel nostro caso il DogId colonna:

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
);

Risultato:

DOGID COGNOME COGNOME
2 Corteccia Fabio
6 Wag Johnson
7 Wag Johnson

Opzione 7

Ed ecco l'altra query con rowid sostituito da DogId colonna:

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

Risultato:

DOGID COGNOME COGNOME
2 Corteccia Fabio
6 Wag Johnson
7 Wag Johnson

Opzione 8

Un altro modo per trovare i duplicati è utilizzare ROW_NUMBER() funzione finestra:

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

Risultato:

DOGID COGNOME COGNOME RIGA_NUM
1 Corteccia Fabio 1
2 Corteccia Fabio 2
4 Ruff Robinson 1
7 Wag Johnson 1
5 Wag Johnson 2
6 Wag Johnson 3
3 Trama Jones 1

Usando la PARTITION La clausola comporta l'aggiunta di una nuova colonna, con un numero di riga che aumenta ogni volta che c'è un duplicato, ma si reimposta di nuovo quando c'è una riga univoca.

In questo caso non raggruppiamo i risultati, il che significa che possiamo vedere ogni riga duplicata, inclusa la relativa colonna dell'identificatore univoco.

Opzione 9

Possiamo anche utilizzare l'esempio precedente come espressione di tabella comune in una query più ampia:

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;

Risultato:

DOGID COGNOME COGNOME RIGA_NUM
2 Corteccia Fabio 2
5 Wag Johnson 2
6 Wag Johnson 3

Tale query esclude i non duplicati dall'output ed esclude una riga di ogni duplicato dall'output.

Opzione 10

Ecco un altro modo per ottenere lo stesso output dell'esempio precedente:

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

Risultato:

DOGID COGNOME COGNOME
2 Corteccia Fabio
6 Wag Johnson
7 Wag Johnson

Questo esempio utilizza MINUS di Oracle operatore, che restituisce solo righe univoche restituite dalla prima query ma non dalla seconda.

Il MINUS l'operatore è simile a EXCEPT operatore in altri DBMS, come SQL Server, MariaDB, PostgreSQL e SQLite.

Opzione 11

Ecco un'altra opzione per selezionare i duplicati dalla nostra tabella:

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
);

Risultato:

DOGID COGNOME COGNOME DOGID COGNOME COGNOME
2 Corteccia Fabio 1 Corteccia Fabio
7 Wag Johnson 5 Wag Johnson
7 Wag Johnson 6 Wag Johnson