Di seguito sono riportati quattro metodi che puoi utilizzare per trovare righe duplicate in SQL Server.
Per "righe duplicate" intendo due o più righe che condividono esattamente gli stessi valori su tutte le colonne.
Dati campione
Supponiamo di avere una tabella con i seguenti dati:
SELECT * FROM Pets;
Risultato:
+---------+-----------+-----------+ | PetId | PetName | PetType | |---------+-----------+-----------| | 1 | Wag | Dog | | 1 | Wag | Dog | | 2 | Scratch | Cat | | 3 | Tweet | Bird | | 4 | Bark | Dog | | 4 | Bark | Dog | | 4 | Bark | Dog | +---------+-----------+-----------+
Possiamo vedere che le prime due righe sono duplicate, così come le ultime tre righe.
Opzione 1
Possiamo utilizzare la seguente query per restituire informazioni sulle righe duplicate:
SELECT
DISTINCT PetId,
COUNT(*) AS "Count"
FROM Pets
GROUP BY PetId
ORDER BY PetId;
Risultato:
+---------+---------+ | PetId | Count | |---------+---------| | 1 | 2 | | 2 | 1 | | 3 | 1 | | 4 | 3 | +---------+---------+
Possiamo espandere il SELECT
elenco per includere più colonne se necessario:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Risultato:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Se la tabella ha un identificatore univoco, possiamo semplicemente rimuovere quella colonna dalla query. Ad esempio, se assumiamo che PetId
colonna è in realtà una colonna della chiave primaria che contiene un ID univoco, potremmo eseguire la seguente query per restituire tutte le righe duplicate, senza contare la colonna della chiave primaria:
SELECT
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetName,
PetType
ORDER BY PetName;
Risultato:
+-----------+-----------+---------+ | PetName | PetType | Count | |-----------+-----------+---------| | Bark | Dog | 3 | | Scratch | Cat | 1 | | Tweet | Bird | 1 | | Wag | Dog | 2 | +-----------+-----------+---------+
Opzione 2
Se desideriamo che vengano restituite solo le effettive righe duplicate, possiamo aggiungere HAVING
clausola:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY PetId;
Risultato:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Opzione 3
Un altro modo per farlo è usare ROW_NUMBER()
funzione con il PARTITION BY
clausola per numerare l'output del set di risultati.
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets;
Risultato:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 1 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 1 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
Il PARTITION BY
La clausola divide il set di risultati prodotto dal FROM
clausola in partizioni a cui viene applicata la funzione. Quando specifichiamo le partizioni per il set di risultati, ogni partizione fa ricominciare la numerazione (cioè la numerazione inizierà da 1 per la prima riga in ogni partizione).
Opzione 4
Se desideriamo che vengano restituite solo le righe in eccesso dai duplicati corrispondenti, possiamo utilizzare la query precedente come espressione di tabella comune, come questa:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
SELECT * FROM CTE WHERE Row_Number <> 1;
Risultato:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
Uno dei vantaggi di questa operazione è che possiamo eliminare le righe duplicate semplicemente cambiando SELECT *
a DELETE
(nell'ultima riga).
Pertanto possiamo utilizzare il codice sopra per vedere quali righe verranno eliminate, e quindi quando siamo soddisfatti di eliminare le righe corrette, possiamo cambiarlo in un DELETE
dichiarazione per eliminarli effettivamente.
In questo modo:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
DELETE FROM CTE WHERE Row_Number <> 1;