- Aide requête

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

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

+0 -0

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à.

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.

+0 -0

(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 ?

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

+0 -0

'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.

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