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

11 façons de trouver des lignes en double qui ont une clé primaire dans Oracle

Voici onze options pour renvoyer des lignes en double dans Oracle Database lorsque ces lignes ont une clé primaire ou une autre colonne d'identifiant unique et que vous souhaitez l'ignorer.

Exemple de données

Nous utiliserons les données suivantes pour nos exemples :

SELECT * FROM Dogs;

Résultat :

DOGID PRÉNOM NOM
1 Aboiement Smith
2 Aboiement Smith
3 Ouaf Jones
4 Ruff Robinson
5 Wag Johnson
6 Wag Johnson
7 Wag Johnson

Les deux premières lignes sont des doublons et les trois dernières lignes sont des doublons. Les lignes en double partagent exactement les mêmes valeurs dans toutes les colonnes, à l'exception de leur colonne clé primaire/identifiant unique.

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 le fait que les clés primaires contiennent des valeurs uniques signifie que nous devons ignorer cette colonne lors de la recherche de 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 pouvons donc ignorer les données de cette colonne lors de la recherche de doublons.

Option 1

Voici notre première option pour renvoyer les doublons :

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

Résultat :

PRÉNOM NOM COMPTER
Wag Johnson 3
Aboiement Smith 2
Ruff Robinson 1
Ouaf Jones 1

Ici, nous avons construit notre requête avec le GROUP BY clause afin que la sortie soit regroupée par les colonnes pertinentes. Nous avons également utilisé le COUNT() fonction pour renvoyer le nombre de lignes identiques. Et nous l'avons classé par nombre dans l'ordre décroissant afin que les doublons apparaissent en premier.

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 ajouter le HAVING clause à notre exemple précédent pour exclure les non-doublons de la sortie :

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

Résultat :

PRÉNOM NOM COMPTER
Wag Johnson 3
Aboiement Smith 2

Option 3

Nous pouvons également vérifier les doublons sur les colonnes concaténées. Dans ce cas, nous utilisons le DISTINCT mot-clé pour obtenir des valeurs distinctes, puis utilisez le COUNT() fonction pour retourner le compte :

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

Résultat :

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

Option 4

Chaque ligne dans Oracle a un rowid pseudo-colonne qui renvoie l'adresse de la ligne. Le rowid est un identifiant unique pour les lignes de la table, et généralement sa valeur identifie de manière unique une ligne dans la base de données (bien qu'il soit important de noter que les lignes de différentes tables qui sont stockées ensemble dans le même cluster peuvent avoir le même rowid ).

Quoi qu'il en soit, nous pouvons construire une requête qui utilise le rowid si nous voulons :

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

Résultat :

DOGID PRÉNOM NOM
2 Aboiement Smith
6 Wag Johnson
7 Wag Johnson

On pourrait remplacer le SELECT * avec DELETE pour effectuer une opération de déduplication sur la table.

Notez que nous aurions pu utiliser le DogId colonne (notre clé primaire) au lieu du rowid si nous voulions. Cela dit, le rowid peut être utile si vous ne pouvez pas utiliser la colonne de clé primaire pour une raison quelconque, ou si la table n'a pas de clé primaire.

Option 5

Voici une autre requête qui utilise le rowid :

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

Résultat :

DOGID PRÉNOM NOM
2 Aboiement Smith
6 Wag Johnson
7 Wag Johnson

Comme pour l'exemple précédent, nous pourrions remplacer le SELECT * avec DELETE pour supprimer les lignes en double.

Option 6

Les deux rowid les options ci-dessus sont idéales si vous devez ignorer complètement la clé primaire dans votre requête (ou si vous n'avez pas du tout de colonne de clé primaire). Cependant, comme mentionné, il est toujours possible de remplacer rowid avec la colonne de clé primaire - dans notre cas, le DogId colonne :

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

Résultat :

DOGID PRÉNOM NOM
2 Aboiement Smith
6 Wag Johnson
7 Wag Johnson

Option 7

Et voici l'autre requête avec le rowid remplacé par le DogId colonne :

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

Résultat :

DOGID PRÉNOM NOM
2 Aboiement Smith
6 Wag Johnson
7 Wag Johnson

Option 8

Une autre façon de trouver des doublons consiste à utiliser le ROW_NUMBER() fonction fenêtre :

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

Résultat :

DOGID PRÉNOM NOM ROW_NUM
1 Aboiement Smith 1
2 Aboiement Smith 2
4 Ruff Robinson 1
7 Wag Johnson 1
5 Wag Johnson 2
6 Wag Johnson 3
3 Ouaf 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 9

Nous pouvons également utiliser l'exemple précédent comme expression de table commune dans une requête plus large :

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;

Résultat :

DOGID PRÉNOM NOM ROW_NUM
2 Aboiement Smith 2
5 Wag Johnson 2
6 Wag Johnson 3

Cette requête exclut les non-doublons de la sortie et exclut une ligne de chaque doublon de la sortie.

Option 10

Voici une autre façon d'obtenir le même résultat que dans l'exemple précédent :

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

Résultat :

DOGID PRÉNOM NOM
2 Aboiement Smith
6 Wag Johnson
7 Wag Johnson

Cet exemple utilise le MINUS d'Oracle qui renvoie uniquement les lignes uniques renvoyées par la première requête mais pas par la seconde.

Le MINUS l'opérateur est similaire à EXCEPT opérateur dans d'autres SGBD, tels que SQL Server, MariaDB, PostgreSQL et SQLite.

Option 11

Voici encore une autre option pour sélectionner les doublons dans notre tableau :

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 PRÉNOM NOM CHIEN PRÉNOM NOM
2 Aboiement Smith 1 Aboiement Smith
7 Wag Johnson 5 Wag Johnson
7 Wag Johnson 6 Wag Johnson