Obtenir la dernière ligne enregistrée par membre

Résolu
sagat06 Messages postés 166 Date d'inscription mercredi 27 juin 2007 Statut Membre Dernière intervention 31 mars 2014 - 13 nov. 2010 à 18:11
gorgonite Messages postés 14 Date d'inscription mercredi 28 juillet 2004 Statut Membre Dernière intervention 17 novembre 2010 - 17 nov. 2010 à 17:10
Bonjour à tous,
je fais face à un souci au niveau d'une de mes requêtes

Voilà un exemple type exposant mon problème:

Je dispose de 3 tables sql sur lesquelles j'effectue une jointure:

Table amis (membre_id,ami_id) 1 membre-plusieurs amis,
Table membre_produits(membre_id,produit_id) 1 membre-plusieurs produits,
Table produit(produit_id,categorie,dispo)

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

En l'attente de vos réponses,
merci d'avance.


Signé Sagat

12 réponses

sagat06 Messages postés 166 Date d'inscription mercredi 27 juin 2007 Statut Membre Dernière intervention 31 mars 2014 1
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'

J'espère que cette fois tout est bon.

Signé Sagat
3
gorgonite Messages postés 14 Date d'inscription mercredi 28 juillet 2004 Statut Membre Dernière intervention 17 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
0
sagat06 Messages postés 166 Date d'inscription mercredi 27 juin 2007 Statut Membre Dernière intervention 31 mars 2014 1
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.

Signé Sagat
0
gorgonite Messages postés 14 Date d'inscription mercredi 28 juillet 2004 Statut Membre Dernière intervention 17 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 ^^)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
sagat06 Messages postés 166 Date d'inscription mercredi 27 juin 2007 Statut Membre Dernière intervention 31 mars 2014 1
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.


Merci encore.

Signé Sagat
0
gorgonite Messages postés 14 Date d'inscription mercredi 28 juillet 2004 Statut Membre Dernière intervention 17 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
)
0
gorgonite Messages postés 14 Date d'inscription mercredi 28 juillet 2004 Statut Membre Dernière intervention 17 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 :)
0
sagat06 Messages postés 166 Date d'inscription mercredi 27 juin 2007 Statut Membre Dernière intervention 31 mars 2014 1
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é.

Merci encore une fois.

Signé Sagat
0
gorgonite Messages postés 14 Date d'inscription mercredi 28 juillet 2004 Statut Membre Dernière intervention 17 novembre 2010
14 nov. 2010 à 13:24
petit oubli dans le WHERE du NOT EXISTS, il faut aussi s'assurer qu'on parle bien du même membre
0
sagat06 Messages postés 166 Date d'inscription mercredi 27 juin 2007 Statut Membre Dernière intervention 31 mars 2014 1
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.

Merci encore.

Signé Sagat
0
sagat06 Messages postés 166 Date d'inscription mercredi 27 juin 2007 Statut Membre Dernière intervention 31 mars 2014 1
16 nov. 2010 à 16:29
Je reviens sur ce topic car il y a finalement une erreur.

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.

On peut donc obtenir plusieurs fois le même membre, pour plusieurs produits. Il suffit juste qu'il les ait ajoutés en dernier.

Je trouve une solution et reviens.

Signé Sagat
0
gorgonite Messages postés 14 Date d'inscription mercredi 28 juillet 2004 Statut Membre Dernière intervention 17 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
0
Rejoignez-nous