2 votes

SQL - SELECTIONNER les doublons entre les ID, mais ne pas afficher les enregistrements si des doublons se produisent pour le même ID

J'ai actuellement le tableau suivant (simplifié à partir du tableau réel) :

+----+-------+-------+
| ID | Name  | Phone |
+----+-------+-------+
|  1 | Tom   |   123 |
|  1 | Tom   |   123 |
|  1 | Tom   |   123 |
|  2 | Mark  |   321 |
|  2 | Mark  |   321 |
|  3 | Kate  |   321 |
+----+-------+-------+

Le résultat que je souhaite obtenir dans l'instruction SELECT est le suivant :

+----+------+-------+
| ID | Name | Phone |
+----+------+-------+
|  2 | Mark |   321 |
|  3 | Kate |   321 |
+----+------+-------+

Je veux sélectionner les doublons uniquement lorsqu'ils se produisent entre deux différents (comme Mark et Kate qui partagent le même numéro de téléphone), mais n'affiche aucun enregistrement pour les ID qui partagent le même numéro de téléphone avec eux-mêmes uniquement (comme Tom).

Quelqu'un pourrait-il m'indiquer comment y parvenir ?

1voto

GMB Points 188687

Vous pouvez utiliser un EXISTS avec une sous-requête corrélée pour s'assurer qu'il existe un autre enregistrement ayant la même phone et un autre id . Nous avons également besoin DISTINCT pour supprimer les doublons dans le jeu de résultats.

SELECT DISTINCT id, name, phone
FROM mytable t
WHERE EXISTS (
    SELECT 1
    FROM mytable t1
    WHERE t1.phone = t.phone AND t1.id <> t.id
)

Démonstration sur DB Fiddle :

| id  | name | phone |
| --- | ---- | ----- |
| 2   | Mark | 321   |
| 3   | Kate | 321   |

0voto

Gordon Linoff Points 213350

Vous pouvez utiliser les fonctions de la fenêtre pour cela :

select t.*
from (select t.*,
             row_number() over (partition by phone, name order by id) as seqnum,
             min(id) over (partition by phone) as min_id,
             max(id) over (partition by phone) as max_id
      from t
     ) t
where seqnum = 1 and min_id <> max_id;

Une autre méthode utilise l'agrégation et une fonction fenêtre :

select phone, name, id
from (select phone, name, id,
             count(*) over (partition by phone) as num_ids
      from t
      group by phone, name, id
     ) pn
where num_ids > 1;

Ces deux solutions ont l'avantage, par rapport à la solution existante (GMB's), de ne faire référence à la "table" qu'une seule fois. Cela peut être un gros avantage si la table est une vue ou une requête complexe. Si les performances sont un problème, je vous encourage à tester plusieurs variantes pour voir laquelle fonctionne le mieux.

0voto

Himanshu Ahuja Points 2849

On peut utiliser une requête corelatée avec group by et having comme ci-dessous

   Select ID, NAME, max(PHONE) From
 (Select * From Table) t group by id, 
          name having
    1= max( 
    case
   When phone in (select phone from 
     table where t.id<>Id) then 1 else 0) 
      end)

enter image description here

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X