Requête SQL Union disjoint

Le problème exposé dans ce sujet a été résolu.

C'est quoi le but ? Récupérer tous les noms qui sont dans user1 mais pas dans user2 ?

Parce que si c'est ça que tu veux, je pense qu'il serait mieux d'écrire quelque chose dans ce goût-là :

1
2
3
4
5
select nom from user1 u1
where not exists (
select nom  from user2 u2
where u1.nom=u2.nom
)

S'il y a des index sur les noms, c'est un parcours de la table user1 et des requêtes quasiment gratuites sur user2.

Pour une différence symétrique, il y a juste à rajouter une union et une requête similaire dans l'autre sens.

+0 -0

QuentinC, tu es sur que ta requête fonctionne ?

JE n'ai absolument pas testé, j'ai tapé le code directement dans la zone de réponse. Mais je suis sûr à 99% que ça fonctionne, moyennant peutêtre des erreurs de syntaxe basiques.

Par contre tu n'as pas répondu à la question la plus importante et pour moi le contexte n'est pas totalement clair: Quel est le but ? Dit autrement, qu'est-ce que tu cherches à obtenir ? Parce que si ça se trouve ma réponse est complètement à l'ouest, et en fait je crois qu'effectivement à te lire maintenant j'ai répondu à une question que tu ne te posais pas.

Si on admet que la table user1 contient {A, B, C, D, E} et user2 {C, D, E, F, G}, alors la requête que j'ai suggéré ce matin te retournera {A, B}, et la remarque qui suit te permettra d'obtenir {A, B, F, G}.

Sans même essayer, je pense que ta requête à toi te renverra {A, B, C, D, E, F, G}. Est-ce bien ce que tu souhaites ? Par contre je ne pense pas que ce soit la manière la plus efficace d'y arriver.

Si tu veux bel et bien {A, B, C, D, E, F; G}, je pense que ceci est plus rapide que ce que tu proposes :

1
2
3
4
select nom from user1
union
select nom from user2 u2
where not exists( select nom from user1 u1 where u1.nom=u2.nom)

A condition qu'il y ait des index sur les noms, à mon avis not in est beaucoup plus lent.

+1 -0

Si on admet que la table user1 contient {A, B, C, D, E} et user2 {C, D, E, F, G}, alors la requête que j'ai suggéré ce matin te retournera {A, B}

QuentinC

Sinon tu as :

1
2
3
select nom from user1
intersect
select nom from user2

… pour obtenir le même résultat.

, et la remarque qui suit te permettra d'obtenir {A, B, F, G}.

QuentinC

A vrai dire la requête que j'ai indiqué retourne {A, B, C, D, E, F, G}, c'est une requête inutile dans le sens où elle est équivalente à :

1
2
3
select nom from user1
union
select nom from user2
+0 -0

QuentinC tu as bien compris :

  • user1 = {A, B, C, D, E}
  • user2 = {C, D, E, F, G}

Et je souhaite obtenir {A, B, F, G}.

Union exclusif

Toutefois j'ai essayer ta requête mais elle ne retourne que {A, B}. Ta requête ressemblerai à ceci :

Difference

Gugelhupf effectivement ta requête est équivalente à un union.

EDIT : Je crois que j'ai trouver une requête, elle me retourne effectivement {A, B, F, G}

1
2
3
SELECT nom FROM user1 WHERE nom NOT IN (SELECT nom FROM user2)
UNION
SELECT nom FROM user2 WHERE nom NOT IN (SELECT nom FROM user1);

Requête équivalente :

1
2
3
SELECT nom FROM user1 WHERE NOT EXISTS (SELECT nom FROM user2 WHERE user1.nom = user2.nom)
UNION
SELECT nom FROM user2 WHERE NOT EXISTS (SELECT nom FROM user1 WHERE user1.nom = user2.nom);

Y a t-il une autre manière de faire ? Ou sinon laquelle des deux est plus efficace ?

+0 -0

Efficace ou pas je ne sais pas, mais par rapport à ton besoin exprimé il existe une autre solution :

1
2
3
4
5
SELECT COALESCE(T1.nom, T2.nom) AS nom
FROM user1 T1
FULL JOIN user2 T2
ON T1.nom = T2.nom
WHERE T1.nom IS NULL OR T2.nom IS NULL;

EDIT : Et encore une autre (plus couteuse) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(
    SELECT T1.nom FROM user1 T1
    EXCEPT
    SELECT T2.nom FROM user2 T2
)
UNION ALL
(
    SELECT T2.nom FROM user2 T2
    EXCEPT
    SELECT T1.nom FROM user1 T1
)
+1 -0

Toutefois j'ai essayer ta requête mais elle ne retourne que {A, B}.

J'avais fait la remarque juste en-dessous, pour te permettre d'arriver à la variante not exists que tu as trouvée par toi-même ensuite.

Tiens, le mot-clé intersect, je ne connaissais pas. ca existe avec MySQL 5.5 ?

Bien joué pour la variante coalesce. Mais je suis d'avis que ça sera très lent.

Un bencmark opposant toutes les solutions serait intéressant. Perso je parie pour la version not exists… mais avec MySQL, pas sûr, certaines requêtes plutôt simples sont inexpliquablement lentes parfois.

+0 -0

Bien joué pour la variante coalesce. Mais je suis d'avis que ça sera très lent.

Un bencmark opposant toutes les solutions serait intéressant. Perso je parie pour la version not exists… mais avec MySQL, pas sûr, certaines requêtes plutôt simples sont inexpliquablement lentes parfois.

QuentinC

Merci :) La variante avec COALESCE est beaucoup plus rapide que la solution avec EXCEPT d'après le plan d'exécution.

Je suis chaud pour faire un benchmark, ce week-end peut-être… ? :P Quels sont les requêtes que vous souhaiteriez-voir mis à part les 2 derniers que j'ai écrit ?

+0 -0

J'avais fait la remarque juste en-dessous, pour te permettre d'arriver à la variante not exists que tu as trouvée par toi-même ensuite.

Oui et merci soit dit en passant ^^

Tiens, le mot-clé intersect, je ne connaissais pas. ca existe avec MySQL 5.5 ?

Je suis en 5.6 et malheureusement toujours pas de INTERSECT

Quels sont les requêtes que vous souhaiteriez-voir mis à part les 2 derniers que j'ai écrit ?

Ça serait intéressant d'ajouter le NOT IN et le NOT EXISTS

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte