Essayant de faire un forum légèrement différent d'un certain tutorial présent sur le site (http://www.siteduzero.com/tutoriel-3-10017-creer-son-forum-de-toutes-pieces.html), je tombe sur un assez gros soucis pour trouver les requêtes SQL exactes. Les bases de données, ça semblait pourtant être mon truc...
Alors, ce qui est différent, c'est que pour moi, un Sujet est une entité faible par rapport à une Catégorie, et un Message est une entité faible par rapport à un Sujet, d'où le certain nombre de clés primaires. Le but principal, c'est qu'une catégorie n'a pas besoin de savoir quels sont ses sujets, même chose pour les sujets et les messages.
En imaginant que je sois sur la page des sujets de la catégorie x : je souhaite afficher le nom des sujets, la date du dernier message et le nom du membre qui l'a posté. Actuellement, deux sujets dans deux catégories différentes :
Sujets :
1 | 1 | Toto
2 | 1 | Tata
Messages :
1 | 1 | 1 | Toto | xxxxx
1 | 1 | 2 | Re : toto | xxxxxx
1 | 1 | 3 | Re : toto | xxxxxx
2 | 1 | 1 | Tata | xxxxx
Alors maintenant, si vous me suivez toujours, je voudrais essayer d'afficher le nom des sujets de la première catégorie, en y ajoutant la date du dernier message et le nom du membre (je pense que le nom ne pose pas de problème). Pour trouver le titre des sujets, je regarde tous les messages qui sont dans la catégorie x et dont le numéro de message est à 1. J'essaye requête sur requête :
SELECT numeroCategorieMessage, numeroSujet, nomSujet, dateMessage, nomPersonnage
FROM f_message
JOIN f_sujet ON (numeroSujet = numeroSujetMessage)
JOIN personnage ON (numeroPersonnageMessage = numeroPersonnage)
WHERE numeroCategorieMessage = 1 AND numeroMessage = 1
ORDER BY dateMessage DESC;
Résultat :
1 | 1 | Tata | 2010-06-17 15:38:32 | Marie
1 | 1 | Toto | 2010-06-17 15:38:32 | Marie
Alors voilà... Tata ne devrait pas apparaître puisqu'il est dans la catégorie 2... J'imagine que ce sont les jointures qui marchent de cette façon, en associant chaque nom de sujet à chaque numéro de catégorie. Mais alors, pour faire ce que je cherche à faire, rien...
Je ne pense pas que le problème vienne de la modélisation, ça doit pouvoir marcher...
Enfin, je ne vais pas en dire plus pour l'instant, ça commence à devenir long...
En espérant que ce ne soit qu'une petite erreur anodine...
Premièrement, utiliser des noms de colonnes lisibles (comme topic_id) serait un plus, parce que là c'est imbitable. Par exemple je n'ai aucune idée de ce que peut signifier numeroMessage.
Les champs souligné sont les clés primaires, j'avais oublié de le préciser.
NumeroMessage, c'est le numéro du message à l'intérieur d'un sujet, lui-même à l'intérieur d'une catégorie. Par exemple, dès que je crée un nouveau sujet (comme celui-ci par exemple), mon message est toujours le message numéro 1, le votre (première réponse) est le numéro 2, et cette deuxième réponse est le numéro 3.
Le sujet créé à pour numéro "max(numeroSujet)+1" par rapport à la catégorie où il se trouve.
Excusez-moi pour les noms, mais je les comprends d'avantage que d'autres façons de les écrire. Quand je regarde cette page → http://www.siteduzero.com/tutoriel-3-10017-creer-son-forum-de-toutes-pieces.html, c'est là que j'ai bien du mal à comprendre...
JOIN f_sujet ON (numeroSujet = numeroSujetMessage)
Selon ta modélisation, l'identifiant d'un sujet est numeroCategorieSujet ET numeroSujet. Or dans ta condition de jointure, tu ne reprends que le numeroSujet.
Lors de l'exécution de la requête, le SGBD fait donc une jointure avec des sujets qui ont le même numéro que dans le message mais qui appartiennent à une autre catégorie.
Selon moi, la bonne condition serait :
JOIN f_sujet ON (numeroSujet = numeroSujetMessage
AND numeroCategorieSujet = numeroCategorieMessage )
Je suppose que comme tu connais d'avance le numéro de catégorie, tu peux le hard-coder en remplaçant numeroCategorieSujet par ce numéro.
A+,
"'But I don't want to go among mad people,' said Alice. 'Oh, you can't help that,' said the cat. 'We're all mad here.'" Lewis Carroll
Ah, merci, c'est très bien vu !
Il fallait joindre les autres tables en utilisant toutes les clés primaires étrangères : une pour f_sujet et deux pour f_catégorie. J'ai pris la même base en corrigeant légèrement, et voilà ce que ça me donne :
SELECT numeroSujet, nomSujet, dateMessage, nomPersonnage FROM f_message
JOIN f_sujet ON (numeroSujet = numeroSujetMessage)
JOIN f_categorie ON (numeroCategorie = numeroCategorieSujet AND numeroCategorie = numeroCategorieMessage)
JOIN personnage ON (numeroPersonnageMessage = numeroPersonnage)
WHERE numeroCategorie = 1
GROUP BY nomSujet
ORDER BY dateMessage DESC;
A priori, ça marche. J'ai ajouté d'autres sujets et d'autres catégorie, pas de soucis.
Et maintenant que je trouve tous les sujets pour une catégorie donnée, je remarque ma petite erreur de départ : ils sont associés à la date du premier message posté, et non le dernier
Alors, après recherche, je pense qu'il faut utiliser GROUP BY.
SELECT max(numeroMessage), numeroSujet, nomSujet, dateMessage, nomPersonnage FROM f_message
JOIN f_sujet ON (numeroSujet = numeroSujetMessage)
JOIN f_categorie ON (numeroCategorie = numeroCategorieSujet AND numeroCategorie = numeroCategorieMessage)
JOIN personnage ON (numeroPersonnageMessage = numeroPersonnage)
WHERE numeroCategorie = 1
GROUP BY nomSujet
ORDER BY dateMessage DESC;
Normalement (sans 100% de conviction), j'utilise max(numeroMessage) pour trouver le dernier message posté et le groupe avec nomSujet (parce qu'un sujet a toujours des messages qui vont de 1 à x).
1 | 3 | Tete | 2010-06-19 14:57:42 | Marie
3 | 2 | Titi | 2010-06-19 14:45:09 | Marie
3 | 1 | Toto | 2010-06-17 15:38:32 | John
Alors, max(numeroMessage) est correct.
Par contre, la dateMessage et le nomPersonnage correspondent au numeroMessage = 1 pour chaque sujet, alors qu'il faudrait qu'ils correspondent au numeroMessage = max(numeroMessage).
Je me demande si c'est toujours compréhensible... pour moi, oui
Ta condition de GROUP BY me laisse un peu perplexe. Je m'explique : si je suis ton raisonnement ici, tu as des messages, avec le sujet et la catégorie auxquelles ils sont rattachés. On a donc des triplets (message, sujet, catégorie) que tu essaye de regrouper selon le sujet. Or, dans le SELECT tu as la dateMessage qui ne pourra pas être agrégée par le SGBD dans le GROUP BY. Tu as testé cette deuxième requête ?
Sinon, pour arriver au résultat que tu décris, je me demande si un select imbriqué ne serait pas plus simple :
SELECT f1.numeroMessage, numeroSujet, nomSujet, f1.dateMessage, f1.nomPersonnage
FROM f_message f1
JOIN f_sujet ON (numeroSujet = f1.numeroSujetMessage)
JOIN personnage ON (f1.numeroPersonnageMessage = numeroPersonnage)
WHERE f1.numeroCategorieMessage = 1
AND f1.numeroMessage =
( SELECT max(f2.numeroMessage) FROM f_message f2
WHERE f1.numeroCategorieMessage = f2.numeroCategorieMessage
AND f1.numeroSujetMessage = f2.numeroSujetMessage )
ORDER BY f1.dateMessage DESC;
Comme tu n'utilise pas de champs de la table catégorie, la jointure avec cette table peut être oubliée ici.
A+,
"'But I don't want to go among mad people,' said Alice. 'Oh, you can't help that,' said the cat. 'We're all mad here.'" Lewis Carroll
Les résultats indiqués venaient de la deuxième requête -> ils me donnaient les bons numéro, mais pas les messages/dates/noms correspondants, en effet.
Cette fois-ci, ça marche !
Juste une petite modification : même si je n'utilise pas de champs de la table catégorie, je suis obligée de faire une jointure, sinon, les résultats sont erronés. La base de données me renvoie finalement tous les sujets, quelle que soit leur catégorie correspondante (je me retrouve avec l'intégralité des sujets dans toutes les catégories...).
C'est ce que j'avais corrigé la première fois sur vos conseils -> rajouter la jointure même si je n'utilise pas de champs, à cause de la clé primaire étrangère multiple.
Voici donc la requête finale :
SELECT f1.numeroMessage, numeroSujet, nomSujet, f1.dateMessage, nomPersonnage FROM f_message f1
JOIN f_sujet ON (numeroSujet = numeroSujetMessage)
JOIN f_categorie ON (numeroCategorie = numeroCategorieSujet AND numeroCategorie = numeroCategorieMessage)
JOIN personnage ON (numeroPersonnageMessage = numeroPersonnage)
WHERE numeroCategorieMessage = $numeroCategorie
AND f1.numeroMessage =
( SELECT max(f2.numeroMessage) FROM f_message f2
WHERE f1.numeroCategorieMessage = f2.numeroCategorieMessage
AND f1.numeroSujetMessage = f2.numeroSujetMessage )
ORDER BY dateMessage DESC;
Mille fois merci pour votre aide !
Jointures difficiles
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
"'But I don't want to go among mad people,' said Alice. 'Oh, you can't help that,' said the cat. 'We're all mad here.'" Lewis Carroll
"'But I don't want to go among mad people,' said Alice. 'Oh, you can't help that,' said the cat. 'We're all mad here.'" Lewis Carroll