Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

3 façons de supprimer les lignes en double dans SQL Server tout en ignorant la clé primaire

Les exemples suivants utilisent T-SQL pour supprimer les lignes en double dans SQL Server tout en ignorant la clé primaire ou la colonne d'identifiant unique.

Plus précisément, les exemples suppriment les lignes en double mais en conservent une. Ainsi, étant donné deux lignes identiques, l'une est supprimée et l'autre reste. Ceci est souvent appelé "déduplication" de la table, "déduplication" de la table, etc.

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, tout comme les trois dernières lignes.

Option 1

Tout d'abord, exécutons le code suivant pour vérifier quelles lignes vont être dédupliquées :

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            |
+---------+-------------+------------+--------------+

Nous avons utilisé le ROW_NUMBER() fonction avec le PARTITION BY clause pour créer notre propre numéro de ligne qui s'incrémente lorsque des doublons sont trouvés et se réinitialise lorsqu'un non-duplicata est trouvé. Un nombre supérieur à 1 indique qu'il s'agit d'un doublon, nous ne renvoyons donc que les lignes dont le nombre est supérieur à 1.

Nous pouvons voir que trois lignes seront supprimées lorsque nous déduplirons cette table.

Dédupliquons maintenant la table :

WITH cte AS 
    (
        SELECT 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
DELETE FROM cte WHERE Row_Number <> 1;

Résultat :

(3 rows affected)

Comme prévu, trois lignes ont été supprimées.

Cette requête est presque identique à la précédente. Tout ce que nous avons fait a été de changer SELECT * sur la dernière ligne pour DELETE .

Maintenant, sélectionnons toutes les lignes du tableau afin de vérifier que les bonnes lignes ont été supprimées :

SELECT * FROM Dogs;

Résultat :

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Nous pouvons voir que chaque chien n'apparaît plus qu'une seule fois dans le tableau.

Option 2

En supposant que la table a été restaurée après l'exemple précédent, voici une autre façon de vérifier les doublons :

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    |
+---------+-------------+------------+

Dans ce cas, nous avons utilisé le EXCEPT opérateur avec le MIN() une fonction. Nous pourrions remplacer MIN() avec MAX() en fonction des lignes que nous voulons supprimer.

Pour supprimer les lignes, nous pouvons simplement remplacer SELECT * avec DELETE :

DELETE FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Résultat :

(3 rows affected)

Et vérifiez ce qui reste :

SELECT * FROM Dogs;

Résultat :

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Option 3

Une autre façon de le faire est de joindre la table sur elle-même et de vérifier les doublons de cette façon.

En supposant que la table a été restaurée après l'exemple précédent, voici notre troisième option pour sélectionner les doublons :

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    |
+---------+-------------+------------+---------+-------------+------------+

Ce résultat n'est pas aussi clair que celui de l'exemple précédent, mais nous pouvons toujours voir quelles lignes sont des doublons.

Nous pouvons maintenant modifier cette requête afin de supprimer les lignes en double :

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    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 :

(3 rows affected)

Encore une fois, trois lignes ont été supprimées.

Vérifions à nouveau le tableau :

SELECT * FROM Dogs;

Résultat :

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Vous remarquerez peut-être que cette fois, les autres lignes ont été supprimées. En d'autres termes, nous avons maintenant DogId s 2, 3, 4 et 7 alors que dans les exemples précédents, il nous restait 1, 3, 4 et 5.

Nous pouvons facilement modifier cet exemple pour supprimer les mêmes lignes que les exemples précédents. Pour ce faire, nous pouvons utiliser le MIN() fonction au lieu de MAX() fonction :

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName 
    AND d1.DogId <> d2.DogId 
    AND d1.DogId=( 
        SELECT MIN(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    )
);