- Aide requête

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour, J'utilise MySQL pour un projet perso et je bloque sur une requête. ça fait plusieurs heures que je me casse la tête sur la conception d'une requête et je n'y arrive toujours pas…

1
2
3
4
5
6
7
8
9
SELECT DISTINCT a_suggestions.points, a_suggestions.titre, a_suggestions.ID, a_wishsCommuns.type, a_couples.idUser1
FROM a_wishsCommuns
LEFT JOIN a_suggestions ON a_suggestions.ID = a_wishsCommuns.idSuggestion
LEFT JOIN a_couples ON a_couples.ID = a_wishsCommuns.idCouple
WHERE (a_wishsCommuns.liste = 1 AND a_wishsCommuns.type = 0
       OR (a_wishsCommuns.type = 1 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser1 = '5'))
       OR (a_wishsCommuns.type = 2 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser2 = '5'))
       OR (a_wishsCommuns.type = 1 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser2 = '5'))
       OR (a_wishsCommuns.type = 2 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser1 = '5')))

Je voudrais faire une requête qui me retourne exactement la même chose que celle ci-dessus en fusionnant les lignes ou a_wishsCommuns.type = 0 et a_Suggestions.ID identique. Je suis aussi preneur pour une requête plus propre que celle-ci. Voici une représentation de mes tables.

Merci d'avance ;)

Édité par cbourree

Qui ne pète ni ne rote est voué à l'explosion. Et si tu cherches encore la poignée c'est que tu te heurtes à un mur

+0 -0
Staff

Cette réponse a aidé l'auteur du sujet

Bon pas facile à analyser tout ça, on va essayer de réduire ensemble cette requête au maximum, même si on dirait qu'il y a un problème de conception derrière tout ça.

Ce qui m'interpelle premièrement c'est le morceaux dans le WHERE qui ressemble à ceci :

1
a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser1 = '5')

Etant donné que tu fais déjà une jointure plus haut entre a_wishsCommuns et a_couples sur les même clés, on est donc certain que ce qui ressortira de la jointure matchera avec a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples) modulo le remplacement de ta jointure à gauche plus haut, par une jointure interne.

En gros on peut déjà remplacer ça :

1
2
3
4
5
6
LEFT JOIN a_couples ON a_couples.ID = a_wishsCommuns.idCouple
WHERE (a_wishsCommuns.liste = 1 AND a_wishsCommuns.type = 0
       OR (a_wishsCommuns.type = 1 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser1 = '5'))
       OR (a_wishsCommuns.type = 2 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser2 = '5'))
       OR (a_wishsCommuns.type = 1 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser2 = '5'))
       OR (a_wishsCommuns.type = 2 AND a_wishsCommuns.idCouple IN (SELECT ID FROM a_couples WHERE idUser1 = '5')))

par

1
2
3
4
5
6
INNER JOIN a_couples ON a_couples.ID = a_wishsCommuns.idCouple
WHERE (a_wishsCommuns.liste = 1 AND a_wishsCommuns.type = 0
       OR (a_wishsCommuns.type = 1 AND a_couples.idUser1 = '5')
       OR (a_wishsCommuns.type = 2 AND a_couples.idUser2 = '5')
       OR (a_wishsCommuns.type = 1 AND a_couples.idUser2 = '5')
       OR (a_wishsCommuns.type = 2 AND a_couples.idUser1 = '5'))

ça permet déjà de réduire un peu les 4 sous requêtes derrière, ce qui est bon pour les perfs.

Mais ce n'est pas tout, car notre nouvelle écriture nous fais voir que l'on peut encore améliorer tout ça. Ce qui est dans le WHERE peut finalement être réduit à :

1
2
3
WHERE (a_wishsCommuns.liste = 1 AND a_wishsCommuns.type = 0
       OR (a_wishsCommuns.type IN (1, 2) AND a_couples.idUser1 = '5')
       OR (a_wishsCommuns.type IN (1, 2) AND a_couples.idUser2 = '5'))

A partir d'ici un autre truc saute encore aux yeux, on a une belle duplication là à factoriser. ça revient à faire ça :

1
2
WHERE (a_wishsCommuns.liste = 1 AND a_wishsCommuns.type = 0
       OR (a_wishsCommuns.type IN (1, 2) AND (a_couples.idUser1 = '5' OR a_couples.idUser2 = '5'))

Si je dois donc réécrire ta requête, je l'aurai faite comme ceci au final :

1
2
3
4
5
6
SELECT DISTINCT s.points, s.titre, s.ID, w.type, c.idUser1
FROM a_wishsCommuns AS w
LEFT JOIN a_suggestions AS s ON s.ID = w.idSuggestion
INNER JOIN a_couples AS c ON c.ID = w.idCouple
WHERE (w.liste = 1 AND w.type = 0
           OR (w.type IN (1, 2) AND (c.idUser1 = '5' OR c.idUser2 = '5'))

Bon je n'ai pas testé, il y a peut-être un cas qui m'ait passé inaperçu ou une erreur de syntaxe, c'est pour cela que je t'expose mon raisonnement pour en arriver là.

Auteur du sujet

Waou !!! Merci ça fonctionne :) (Si on ajoute une parenthèse à la fin)

Cependant pour l'instant je fusionne les lignes qui ont le type 0 et qui ont le même s.ID en JS. Est-ce possible de le faire directement dans la requête ?

S'en va lire un cours sur les différentes jointures

Encore merci <3 PS : C'est dommage qu'on ne puisse pas mettre des petites images tels que mes valeurs retournées actuelles sur zestdesavoir.com sans avoir à passé par un hébergeur.

Qui ne pète ni ne rote est voué à l'explosion. Et si tu cherches encore la poignée c'est que tu te heurtes à un mur

+0 -0
Staff

(Si on ajoute une parenthèse à la fin)

Je savais que j'avais laissé passé une erreur de syntaxe :)

Cependant pour l'instant je fusionne les lignes qui ont le type 0 et qui ont le même s.ID en JS. Est-ce possible de le faire directement dans la requête ?

Je ne suis pas sur de bien voir ce que tu cherches à obtenir (dommage que tu n'arrive pas à uploader une image de tes données, ça aiderait vachement).

Cependant, si tu veux fusionner quelque chose, tu dois avoir des règles de fusion. Dans ton cas, ta requête renvoi 5 colonnes :

Comment détermine tu la ligne que tu choisis lorsque 2 lignes ont des attributs différents. Par exemple si tu as ceci :

s.points s.titre s.ID w.type c.idUser1
1 toto 1 0 1
2 tata 1 0 2
3 tutu 1 0 3

Quelle est ta règle de fusion ? Quelle ligne (et surtout son contenu) souhaites tu obtenir après ta fusion ?

Auteur du sujet

BDD Voilà un exemple de résultat de la requête actuelle. Je voudrais fusionné les lignes 4 et 5 'Premiere sug' car celles ci étaient liées à un wishsCommuns de type 0 et corresponde à une même suggestion. La colonne idUser1 n'a aucun sens logique dans mon cas.

Encore merci pour vos réponse

Édité par cbourree

Qui ne pète ni ne rote est voué à l'explosion. Et si tu cherches encore la poignée c'est que tu te heurtes à un mur

+0 -0
Staff

'Premiere sug' car celles ci étaient liées à un wishsCommuns de type 0 et corresponde à une même suggestion. La colonne idUser1 n'a aucun sens logique dans mon cas.

Tu veux dire que tu t'en fou de la valeur de idUser1 ?

  • Si oui, il te suffit de virer c.idUser1 de ton SELECT et le DISTINCT s'occupera de faire la fusion. Mais du coup, tu n'aura plus cette colonne accessible directement si tu voulait l'utiliser
  • Si non, il faut que tu nous dise laquelle des valeurs tu veux attribuer à idUser1 en fusionnant la ligne 4 et la ligne 5.
Auteur du sujet

Je m'en fou pour les lignes 4 et 5 qui ont un type 0. Peut importe la valeur que je récupère d'idUser1 dans ce cas là. J'en ai besoin pour les autres lignes.

Qui ne pète ni ne rote est voué à l'explosion. Et si tu cherches encore la poignée c'est que tu te heurtes à un mur

+0 -0
Staff

Cette réponse a aidé l'auteur du sujet

Dans ce cas, on pourrait modifier la requête initiale dans ce sens :

1
2
3
4
5
6
7
SELECT DISTINCT s.points, s.titre, s.ID, w.type, MAX(c.idUser1) as idUser
FROM a_wishsCommuns AS w
LEFT JOIN a_suggestions AS s ON s.ID = w.idSuggestion
INNER JOIN a_couples AS c ON c.ID = w.idCouple
WHERE (w.liste = 1 AND w.type = 0
           OR (w.type IN (1, 2) AND (c.idUser1 = '5' OR c.idUser2 = '5')))
GROUP BY s.points, s.titre, s.ID, w.type
Auteur du sujet

C'est à ce genre d'astuce qu'on reconnais les pros… Merci beaucoup c'est exactement ce que je voulais <3

Qui ne pète ni ne rote est voué à l'explosion. Et si tu cherches encore la poignée c'est que tu te heurtes à un mur

+0 -0
Auteur du sujet

Oui c'est ce que je fais ;) PS : tu avais encore oublié des parenthèses pour les priorités entre AND et OR ^^ (Mais ça je sais faire)

Qui ne pète ni ne rote est voué à l'explosion. Et si tu cherches encore la poignée c'est que tu te heurtes à un mur

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

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