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

7 façons de trouver des lignes en double dans PostgreSQL tout en ignorant la clé primaire

Voici sept façons de renvoyer des lignes en double dans PostgreSQL lorsque ces lignes ont une clé primaire ou une autre colonne d'identifiant unique.

Cela signifie que les lignes en double partagent exactement les mêmes valeurs dans toutes les colonnes, à l'exception de leur colonne de clé primaire/ID unique.

Exemple de données

Nous utiliserons les données suivantes pour nos exemples :

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

Les deux premières lignes sont des doublons (sauf pour le DogId colonne, qui est la clé primaire de la table et contient une valeur unique sur toutes les lignes). Les trois dernières lignes sont également des doublons (sauf pour le DogId colonne).

La colonne de clé primaire garantit qu'il n'y a pas de lignes en double, ce qui est une bonne pratique dans les SGBDR, car les clés primaires aident à renforcer l'intégrité des données. Mais comme les clés primaires empêchent les lignes en double, elles peuvent interférer avec notre capacité à trouver des doublons.

Dans notre tableau ci-dessus, la colonne de clé primaire est un nombre incrémentiel, et sa valeur n'a aucune signification et n'est pas significative. Nous devons donc ignorer cette ligne si nous voulons trouver des doublons dans les autres colonnes.

Option 1

Nous pouvons utiliser le SQL GROUP BY clause pour regrouper les colonnes par leurs colonnes significatives, puis utilisez le COUNT() fonction pour retourner le nombre de lignes identiques :

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

Résultat :

 firstname | lastname | count 
-----------+----------+-------
 Ruff      | Robinson |     1
 Wag       | Johnson  |     3
 Woof      | Jones    |     1
 Bark      | Smith    |     2

Ici, nous avons exclu la colonne de clé primaire 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). Les deux autres lignes n'ont pas de doublons.

Option 2

Nous pouvons exclure les non-doublons de la sortie avec le HAVING clause :

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

Voici un exemple de vérification des doublons sur les colonnes concaténées. Dans ce cas, nous utilisons le CONCAT() fonction pour concaténer nos deux colonnes, utilisez le DISTINCT mot-clé pour obtenir des valeurs distinctes, puis utilisez le COUNT() fonction pour retourner le compte :

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

Résultat :

    dogname    | count 
---------------+-------
 Wag Johnson   |     3
 Ruff Robinson |     1
 Woof Jones    |     1
 Bark Smith    |     2

Option 4

Nous pouvons également utiliser le ROW_NUMBER() fonction fenêtre :

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

Utilisation de la PARTITION La clause entraîne l'ajout d'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.

Dans ce cas, nous ne regroupons pas les résultats, ce qui signifie que nous pouvons voir chaque ligne en double, y compris sa colonne d'identifiant unique.

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

Cela exclut les non-doublons de la sortie et exclut une ligne de chaque doublon de la sortie. En d'autres termes, il ne montre que les lignes excédentaires des doublons. Ces lignes sont les meilleures candidates pour être supprimées lors d'une opération de déduplication.

Option 6

Voici une manière plus concise 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 
-------+-----------+----------
     6 | Wag       | Johnson
     2 | Bark      | Smith
     7 | Wag       | Johnson

Une différence entre cet exemple et le précédent est que cet exemple ne nécessite pas de générer notre propre numéro de ligne séparé.

Option 7

Voici encore une autre option pour renvoyer des lignes en double dans Postgres :

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