Mon objectif est d'obtenir le dernier produit enregistré (son id et sa catégorie) par chacun de mes amis (donc une seule ligne / ami ) et qui est dispo (=1) (en réalité je fait un LIMIT 5 pour n'obtenir qu'un échantillon d'ami)
Dans mon raisonnement (sans utiliser le LIMIT), j'ai d'abord cherché à obtenir tout les produits enregistrés de mes amis et qui sont dispos
Voilà ma requête:
> SELECT A.ami_id,B.produit_id,C.categorie FROM amis A JOIN membre_produits B ON (A.ami_idB.membre_id AND A.membre_id='mon_id') JOIN produit C ON (B.produit_id=C.produit_id) WHERE C.dispo='1'
1) Trouvez-vous cette requête correcte ? Pour ma part, elle me renvoie comme résultat ce que j'en attend.
A partir de là, j'ai cherché à obtenir seulement un produit unique par ami (toujours sans me soucier du LIMIT)
Voilà la requête que j'utilise à cet effet:
> SELECT max(B.produit_id),B.membre_id,C.categorie,C.produit_id FROM membre_produits B JOIN amis A ON (A.ami_idB.membre_id AND A.membre_id='mon_id') JOIN produit C ON (B.produit_id=C.produit_id) WHERE C.dispo='1' GROUP BY B.membre_id
2) Là aussi que pensez-vous de cette requête ?
Elle me renvoie bien 1 seule ligne par ami et l'id max des produits d'un ami, mais les autres infos ne correspondent pas à celle de l'id_max mais
au premier produit enregistré dans la table alors que je cherche à avoir le dernier !
Sachant qu'un membre effectue cette requête de temps en temps, il obtient quoiqu'il arrive les mêmes résultats peu importe si de nouveaux produits ont été ajoutés par un de ses amis.
Avez-vous des idées, des directions, des suggestions à me proposer ?
NB: j'ai mis de côté DISTINCT car il me semble que je ne peux l'utiliser sur une seule des colonnes d'une table
sagat06
Messages postés166Date d'inscriptionmercredi 27 juin 2007StatutMembreDernière intervention31 mars 20141 16 nov. 2010 à 16:39
Voilà, j'ai amélioré la précédente requête.
J'ai changé la clause d'égalité dans la sous requête:
D.produit_id=B.produit_id devient D.membre_id=B.membre_id.
C'est fou comme tout parait logique après coup.
SELECT A.ami_id,B.produit_id,C.categorie FROM amis A JOIN membre_produits B ON (B.membre_id=A.ami_id) JOIN produit C ON (B.produit_id=C.produit_id) WHERE NOT EXISTS (SELECT * FROM membre_produits D WHERE D.quand>B.quand AND D.membre_id=B.membre_id) AND A.membre_id='".$a."' AND C.dispo='1'
gorgonite
Messages postés14Date d'inscriptionmercredi 28 juillet 2004StatutMembreDernière intervention17 novembre 2010 13 nov. 2010 à 20:21
si tu avais un moyen de "dater" l'association membre/produit, il te serait possible de faire un WHERE NOT EXISTS pour ne garder que l'association la plus récente de chaque utilisateur
sagat06
Messages postés166Date d'inscriptionmercredi 27 juin 2007StatutMembreDernière intervention31 mars 20141 13 nov. 2010 à 20:50
Merci d'avoir pris le temps de répondre.
J'évitais justement de devoir dater cette association car je n'en ai aucune utilité, en dehors de celle que tu me proposes.
De plus, je ne sais pas du tout me servir de WHERE NOT EXISTS, pourrais-tu me donner un exemple simple à partir de mon cas avec la table membre_produit (membre_id,produit_id,date).
Sinon, j'ai finalement réussi à obtenir ce que je voulais mais la requête semble assez complexe. Je vous laisse en juger:
SELECT A.membre_id,A.produit_id,D.categorie FROM membre_produits A JOIN (SELECT Max(produit_id) As prod,membre_id FROM membre_produits GROUP BY membre_id) As B ON (B.prod=A.produit_id AND A.membre_id=B.membre_id) JOIN amis C ON (C.ami_id=A.membre_id AND C.membre_id='mon_id') JOIN produit D ON (D.produit_id=A.produit_id)
Cette requête me donne bien ce que je recherche: uniquement le dernier produit enregistré et sa catégorie pour chacun de mes amis.
Mais n'est-elle pas trop complexe, en sachant qu'elle sera executée avec un LIMIT 5 quasi généralement ?
Toujours en l'attente de vos avis, idées, critiques...
merci d'avance.
gorgonite
Messages postés14Date d'inscriptionmercredi 28 juillet 2004StatutMembreDernière intervention17 novembre 2010 14 nov. 2010 à 12:24
pas d'accord avec ton raisonnement qui suppose que les amis vont faire des associations membre/produits au fur et à mesure de l'ajout des produits dans l'inventaire... d'où le MAX(produit_id)
Il s'agit d'une énorme supposition sur les scénarios possibles... et ça doit marcher surtout sur ton cas de test (cf Myers 79 si tu veux être convaincu que des bons tests ne suffisent pas -- déformation professionnelle venant de l'analyse statique)
je reviens avec un exemple de requête plus tard... (mauvaise manip, j'ai tout perdu mon beau message, donc je refais au propre et je poste ^^)
Vous n’avez pas trouvé la réponse que vous recherchez ?
sagat06
Messages postés166Date d'inscriptionmercredi 27 juin 2007StatutMembreDernière intervention31 mars 20141 14 nov. 2010 à 12:32
En fait, l'exemple que je prend est un cas particulier ou le produit_id définit justement l'ordre chronologique: supposons des ventes flash journalières uniques sur 1 seul produit.
A 1 journée ne peut donc correspondre qu'un seul produit_id.
J'aurais dû préciser cela, je m'en excuse.
Cependant, vu qu'en règle générale, tel n'est pas le cas, je suis toujours intéressé par ton exemple de requête.
gorgonite
Messages postés14Date d'inscriptionmercredi 28 juillet 2004StatutMembreDernière intervention17 novembre 2010 14 nov. 2010 à 12:48
je trouve pas comment éditer le post...
un premier jet, mais j'ai pas de SGBD sous la main pour tester (vive les WE en famille ^^)
SELECT A.ami_id,B.produit_id,C.categorie
FROM amis A
JOIN membre_produits B ON (B.membre_id=A.ami_id)
JOIN produits C ON (B.produit_id=C.produit_id)
WHERE A.membre_id='mon_id' AND C.dispo='1' AND
NOT EXISTS (
SELECT * FROM membre_produits D WHERE D.date>B.date
)
gorgonite
Messages postés14Date d'inscriptionmercredi 28 juillet 2004StatutMembreDernière intervention17 novembre 2010 14 nov. 2010 à 12:52
au passage, il faudrait peut-être optimiser ton schéma de base... le C.dispo='1' me semble suspect, de même cette grosse requête peut devenir une procédure stockée et préciser les INNER/OUTER JOIN :)
sagat06
Messages postés166Date d'inscriptionmercredi 27 juin 2007StatutMembreDernière intervention31 mars 20141 14 nov. 2010 à 12:59
Ok, je teste la requête dans l'aprèm et reviens avec mes observations.
Pour les INNER/OUTER JOIN, je n'ai rien préciser considérant qu'il s'agit par défaut de INNER JOIN.
Le C.dispo='1' n'est qu'une info quand à la disponibilité du produit => vente flash journalière d'un produit non limité en quantité. C'est un peu tiré par les cheveux, j'en conviens mais de toute manière cette condition devrait la plupart du temps être vérifié.
Pour les procédures stockées, faut que je me renseigne. Je sais que ça existe mais n'en ai jamais utilisé.
sagat06
Messages postés166Date d'inscriptionmercredi 27 juin 2007StatutMembreDernière intervention31 mars 20141 14 nov. 2010 à 16:39
Re,
en testant ta requête et la modifiant légèrement, j'obtiens un résultat intéressant. Pour cela, j'ai rajouté des dates aléatoires sur les associations membre/produit
Voilà la requête finale:
SELECT A.ami_id,B.produit_id,C.categorie FROM amis A JOIN membre_produits B ON (B.membre_id=A.ami_id) JOIN produit C ON (B.produit_id=C.produit_id) WHERE NOT EXISTS (SELECT * FROM membre_produits D WHERE D.quand>B.quand AND D.produit_id=B.produit_id) AND A.membre_id='".$a."' AND C.dispo='1' ";
J'ai donc rajouté dans la requête incluse dans le NOT EXISTS l'égalité D.produit_id=B.produit, sans cela je n'obtenais aucun résultat (num_rows=0)
Résultat: la requête me retourne bien le dernier produit enregistré par chacun de mes amis, bien que là aussi elle me paraisse bien complexe. Pour info les colonnes ami_id,membre_id,produit_id sont indexées, et cette requête ne sera exécutée qu'1 seule fois par membre sur une page donnée (résultat stockée dans une session et réutilisée durant une période donnée -30/40 mn- avant d'être ré-exécuté, etc...)
Ne me reste plus qu'à tester les performances des différentes requêtes me donnant le même résultat, et de m'intéresser aux procédures stockées.
gorgonite
Messages postés14Date d'inscriptionmercredi 28 juillet 2004StatutMembreDernière intervention17 novembre 2010 17 nov. 2010 à 17:10
[quote=sagat06]La requête précédente me donne en réalité la dernière entrée d'un produit unique et non pas le dernier produit d'un membre unique. /quote
en effet, je avais indiqué d'ajouter un test pour le membre...
[quote=gorgonite]petit oubli dans le WHERE du NOT EXISTS, il faut aussi s'assurer qu'on parle bien du même membre/quote