Voici sept options pour rechercher des lignes en double dans SQL Server, lorsque ces lignes ont une clé primaire ou une autre colonne d'identifiant unique.
En d'autres termes, le tableau contient deux ou plusieurs lignes qui partagent exactement les mêmes valeurs dans toutes les colonnes, à l'exception de sa colonne d'identifiant unique.
Exemple de données
Supposons que nous ayons un tableau avec les données suivantes :
SELECT * FROM Dogs;
Résultat :
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +---------+-------------+------------+
Nous pouvons voir que les deux premières lignes sont des doublons (sauf pour le DogId
colonne, qui contient une valeur unique sur toutes les lignes et peut être utilisée comme colonne de clé primaire de la table). Nous pouvons également voir que les trois dernières lignes sont des doublons (sauf pour le DogId
colonne).
La colonne d'ID unique garantit qu'il n'y a pas de lignes en double, ce qui est normalement un trait hautement souhaitable dans les SGBDR. Cependant, dans ce cas, il a le potentiel d'interférer avec notre capacité à trouver des doublons. Par définition, la colonne d'ID unique garantit qu'il n'y a pas de doublons. Heureusement, nous pouvons résoudre ce problème assez facilement, comme le montrent les exemples suivants.
Option 1
La façon la plus simple/la plus simple de le faire est probablement avec une requête simple qui utilise le GROUP BY
clause :
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Résultat :
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Bark | Smith | 2 | +-------------+------------+---------+
Nous avons pu exclure la colonne clé primaire/identifiant unique en l'omettant de notre requête.
Le résultat nous indique qu'il y a trois lignes contenant Wag Johnson et deux lignes contenant Bark Smith. Ce sont des doublons (ou des triples dans le cas de Wag Johnson).
Option 2
Nous pouvons exclure les non-doublons du résultat en incluant le HAVING
clause dans notre requête :
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Résultat :
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Bark | Smith | 2 | +-------------+------------+---------+
Option 3
Nous pouvons également vérifier les doublons sur les colonnes concaténées. Par exemple, nous pouvons utiliser le CONCAT()
fonction pour concaténer nos deux colonnes :
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Résultat :
+---------------+---------+ | DogName | Count | |---------------+---------| | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+---------+
Option 4
Nous pouvons utiliser le ROW_NUMBER()
fonction avec le PARTITION BY
clause pour créer une nouvelle colonne avec un numéro de ligne qui s'incrémente à chaque fois qu'il y a un doublon, mais se réinitialise à nouveau lorsqu'il y a une ligne unique :
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Résultat :
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 5 | Wag | Johnson | 1 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +---------+-------------+------------+--------------+
L'un des avantages de cette méthode est que nous pouvons voir chaque ligne en double, ainsi que sa colonne d'identifiant unique, car nous ne regroupons pas les résultats.
Option 5
Nous pouvons également utiliser l'exemple précédent comme expression de table commune dans une requête plus large :
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs
)
SELECT * FROM cte WHERE Row_Number <> 1;
Résultat :
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +---------+-------------+------------+--------------+
Cette option exclut les non-doublons de la sortie.
Il exclut également exactement une ligne de chaque doublon de la sortie. Cela nous ouvre la porte pour activer le dernier SELECT *
dans un DELETE
pour dédupliquer la table tout en gardant un exemplaire de chaque doublon.
Option 6
Voici une manière plus succincte d'obtenir le même résultat que dans l'exemple précédent :
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Résultat :
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Cet exemple ne nécessite pas de générer notre propre numéro de ligne séparé.
Option 7
Et enfin, voici une technique un peu plus compliquée pour renvoyer des lignes en double :
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
);
Résultat :
+---------+-------------+------------+---------+-------------+------------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | |---------+-------------+------------+---------+-------------+------------| | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +---------+-------------+------------+---------+-------------+------------+
Même le résultat semble plus alambiqué, mais bon, il nous montre toujours les doublons !