1
votes

Faire correspondre la valeur en double de 2 colonnes et 1 valeur unique de 1 colonne mysql

J'ai ce tableau, voici mon db Fiddle

ID  Val Val2    Val3

4   20  100 SD2
5   20  100 SD1
19  100 200 ab
200 100 200 ae
6   112 100 aa
7   112 100 ab
9   30  90  SF2
10  30  90  SF1

Je veux le résultat avec cette condition

  1. Val devait être dupliqué ET
  2. Val2 devait être dupliqué ET

Après avoir obtenu la valeur en double, je dois maintenant vérifier le val3 à partir de la valeur en double si la valeur de val3 avait une valeur unique de l'agrégat précédent

j'ai essayé avec cette requête

INSERT INTO table1
  (`ID`, `Val`, `Val2`, `Val3`)
VALUES
  ('1','100','200','aa'),
  ('2','100','200','aa'),
  ('3','100','200','aa'),
  ('19','100','200','ab'),
  ('200','100','200','ae'),
  ('4','20','100','SD2'),
  ('5','20','100','SD1'),
  ('6','112','100','aa'),
  ('7','112','100','ab'),
  ('8','90','200','aa'),
  ('9','30','90','SF2'),
  ('10','30','90','SF1');

Je pense que le résultat serait comme ceci

ID  Val Val2    Val3

4   20  100 SD2
5   20  100 SD1
6   112 100 aa
7   112 100 ab
9   30  90  SF2
10  30  90  SF1

BUt j'ai obtenu le résultat comme ceci

INSERT INTO table1
  (`ID`, `Val`, `Val2`, `Val3`)
VALUES
  ('1','100','200','aa'),
  ('2','100','200','aa'),
  ('3','100','200','aa'),
  ('19','100','200','ab'),
  ('4','20','100','SD2'),
  ('5','20','100','SD1'),
  ('6','112','100','aa'),
  ('7','112','100','ab'),
  ('8','90','200','aa'),
  ('9','30','90','SF2'),
  ('10','30','90','SF1');

Exemple 2

ID  Val Val2    Val3
1   100 200 90
2   100 200 10
4   20  100 55
5   20  100 10
9   30  90  180
10  30  90  29

Résultat attendu 2

INSERT INTO table1
  (`ID`, `Val`, `Val2`, `Val3`)
VALUES
  ('1','100','200','90'),
  ('2','100','200','10'),
  ('3','100','200','20'),
  ('19','100','200','20'),
  ('4','20','100','55'),
  ('5','20','100','10'),
  ('6','112','100','20'),
  ('7','112','100','20'),
  ('8','90','200','90'),
  ('9','30','90','180'),
  ('10','30','90','29');

dbfiddle 2

Exemple 3

XXX

Résultat attendu 3

ID  Val Val2    Val3
9   30  90  180
10  30  90  29

Certaines personnes peuvent être confondues avec l'exemple 3, voici donc une note pour l'échantillon 3:

Dans ce cas, l'ID 19 de l'échantillon 3 avait la même valeur avec la colonne val et val2 pour les id 1, 2, 3 (100 et 200), mais ces id (1, 2, 3) avaient le même aa valeur dans val3 , donc id 1,2,3 doit être exclu, car ces id ne correspondaient pas à la dernière condition (val, val2, val3) est unique. L'ID 19 est bien mais la colonne val dan val2 qui avait une valeur en double qui est l'id 1,2, et 3 avait déjà exclu, cela fait que l'id 19 n'avait pas de valeur en double pour les deux colonne val et val2. s'il y avait d'autres données comme '200', '100', '200', 'ae' dans l'échantillon 3, l'id 19 sera inclus dans le résultat car il a une valeur en double à côté d'id 1,2 et 3.

pour l'échantillon 3, l'ID 19 sera inclus si les données du tableau1 étaient comme ceci

Exemple 3 (cas différent)

ID  Val Val2    Val3
1   100 200 90
2   100 200 10
3   100 200 20
4   20  100 55
5   20  100 10
9   30  90  180
10  30  90  29

Le résultat attendu sera comme ça

SELECT
    t1.* 
FROM
    table1 t1 
WHERE
    EXISTS (
    SELECT
        1 
    FROM
        table1 
    WHERE
        ID <> t1.ID 
        AND Val = t1.Val 
        AND Val2 = t1.Val2 
    ) 
    AND NOT EXISTS (
    SELECT
        1 
    FROM
        table1 
    WHERE
        Val = t1.Val 
        AND Val2 = t1.Val2 
    AND Val3 IN ( 
    SELECT Val3 
    FROM table1 
    GROUP BY Val3 
    HAVING count( * ) > 1 
    ) 
)


6 commentaires

Pourquoi ces varchars?


c'est juste un type de données, rien de spécial. @Fraise


Pourquoi 3 est-il exclu du résultat souhaité?


@ Fraise, je suis désolé, on dirait que cette partie me manque, je l'éditerais


Je dois admettre que j'ai du mal à voir comment le résultat 3 correspond à l'ensemble de données 3


@Strawberry j'ai manqué une partie, édité


3 Réponses :


1
votes

Si j'ai bien compris votre question, vous voulez des lignes dont le tuple (val, val2) n'est pas unique et dont (val, val2, val3) est unique.

p> Voici une façon d'exprimer cela en filtrant l'ensemble de données avec la sous-requête corrélée:

select id, val, val2, val3
from (
    select 
        t1.*,
        count(*) over(partition by val, val2) cnt_1,
        count(*) over(partition by val, val2, val3) cnt_2
    from table1 t1
) t
where cnt_1 > 1 and cnt_2 = 1

Pour les performances, considérez un index sur (val, val1, val2) (l'ordre des colonnes dans l'index compte ici).

Si vous avez la chance d'exécuter MySQL 8.0, cela peut être formulé plus simplement et plus efficacement en utilisant les fonctions de fenêtre:

select t1.*
from table1 t1
where 
    (
        select count(*) 
        from table1 t2 
        where t2.val = t1.val and t2.val2 = t1.val2
    ) > 1
    and (
        select count(*)
        from table1 t2
        where t2.val = t1.val and t2.val2 = t1.val2 and t2.val3 = t1.val3
    ) = 1
order by id


5 commentaires

c'est la réponse la plus proche que je puisse savoir, mais cela semble fonctionner !!!


mais à partir de l'exemple 3, il renvoie false, voir ce violon dbfiddle.uk/…


@Gagantous: la ligne avec l'ID 19 semble correspondre aux conditions que vous avez décrites, pourquoi ne la voulez-vous pas dans le jeu de résultats?


même l'id 19 de l'échantillon 3 avait la même valeur avec la colonne val et val2 pour l'id 1, 2, 3 (100 et 200), mais ces id avaient le même aa valeur dans val3 , donc id 1,2,3 doit être exclu, car ces id ne correspondaient pas à la dernière condition (val, val2, val3) est unique. < / code> ID 19 est bien mais val dan val2 colonne qui avait une valeur en double qui est id 1,2, et 3 avait déjà exclu, cela fait que l'id 19 n'avait pas de doublon valeur pour les deux colonnes val et val2 . s'il y avait d'autres données comme '200', '100', '200', 'ae' dans l'échantillon 3, l'id 19 sera inclus dans le résultat car il a une valeur en double à côté de l'id 1,2, et 3


ok j'ai ajouté quelques notes et une autre condition pour l'échantillon 3



1
votes

Joignez le tableau aux requêtes qui appliquent vos conditions:

select distinct t.*
from (
  select val, val2
  from table1
  group by val, val2
  having count(*) > 1
) t1 
inner join (
 select val, val2, val3
  from table1
  group by val, val2, val3
  having count(*) = 1
) t2 
on t2.val = t1.val and t2.val2 = t1.val2
inner join (
 select val, val2, val3
  from table1
  group by val, val2, val3
  having count(*) = 1
) t3 
on t3.val = t1.val and t3.val2 = t1.val2 and t3.val3 <> t2.val3
inner join table1 t on t2.val = t.val and t2.val2 = t.val2 and t.val3 in (t2.val3, t3.val3)

Voir demo1 , demo2 , demo2 "https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=00b86a121fc46293cca42957c2311fb2" rel = "nofollow noreferrer"> demo3 , demo4 .


6 commentaires

pour la démo 3, le résultat n'est toujours pas ce que j'attends, je vais mettre à jour quelques détails


@Gagantous votre conclusion est que l'id 19 sera inclus dans le résultat Ne voulez-vous pas dire par là que l'id = 19 sera inclus?


@Gagantous J'ai édité le lien pour la démo3 et il renvoie vos résultats attendus.


oui c'est vraiment ce à quoi je m'attends, mais quand je supprime les données avec l'id 200 dans la table1, l'id 19 est toujours intact dans la requête de résultat, alors qu'il doit être exclu car l'id 19 dans le résultat final n'avait pas de valeur en double


@Gagantous très bien si cela a fonctionné et n'oubliez pas d'accepter la réponse.


J'attendrais peut-être 2 jours de plus, s'il n'y a pas d'autre réponse, je marquerai ceci comme réponse acceptée



1
votes

Comme @GMB l'a dit de manière assez simplifiée dans sa réponse, vous voulez des lignes dont le tuple (val, val2) n'est pas unique, et dont (val, val2, val3) code> est unique.

La requête suivante devrait accomplir cela très facilement:

   select t.*
from table1 t
inner join
(
select t1.val, t1.val2
from table1 t1
 inner join
  (select val,val2,val3
    from table1
    group by val,val2,val3
    having count(val3) = 1
  ) t2
 on t1.val = t2.val and t1.val2 = t2.val2 and t1.val3 = t2.val3
 group by t1.val, t1.val2
 having count(distinct t1.id) > 1
) tmp
on tmp.val = t.val and tmp.val2 = t.val2
inner join
(select val,val2,val3
    from table1
    group by val,val2,val3
    having count(val3) = 1
  ) t3
 on t.val = t3.val and t.val2 = t3.val2 and t.val3 = t3.val3

Veuillez trouver le lien violon pour Sample1 , Sample2 , Sample3 et Sample4 .


2 commentaires

si j'ai utilisé l'exemple 3, le résultat n'est pas ce à quoi je m'attendais, voir ce violon dbfiddle.uk /…


J'ai mis à jour la réponse et ajouté une démo de violon pour les 4 exemples de données. Veuillez jeter un œil une fois.