Partage
  • Partager sur Facebook
  • Partager sur Twitter

ORDER BY et sous requête

Sujet résolu
    23 avril 2011 à 23:17:38

    Salut à tous

    Afin de compléter mon site, je code un forum en PHP.
    Il est totalement achevé, tout marche à merveille, sauf un truc : l'ordre des posts lors de leur affichage !

    J'ai deux tables.

    L'une contient les reponses (appelons la.. "reponses" !)
    L'autre contient les sujets (on l'appellera bah.. "sujets" ?)

    Mais ma table sujets contient aussi le premier message du sujet (le post initial quoi) !

    Moi, j'aimerais trier un peu comme sur tous les forums. En gros :
    S'il y a au moins une réponse qui a été donnée, on trie avec le timestamp de la dernière réponse, et sinon, avec le timestamp du premier post. Déjà, ces timestamps sont stockés dans leurs tables respectives, donc faut les récupérer à deux endroits !..

    Donc, vu qu'un code vaut mieux que mon charabia, en simplifiant le plus possible, voici mon "code type" (l'original fait 7 lignes :D)

    SELECT s.titre
    FROM sujets AS s
    ORDER BY (SELECT r.timestamp FROM reponses AS r WHERE forum_rattache = ''.$id_forum.'' ORDER BY r.timestamp DESC LIMIT 0,1), s.timestamp DESC
    


    Sauf que, non seulement ça marche pas comme je voudrais, mais en plus, ça irait même pas si ça marchait car tous les messages avec une réponse passeraient avant..

    Sauriez vous svp m'aider ? :(
    Merci par avance !
    • Partager sur Facebook
    • Partager sur Twitter
      24 avril 2011 à 10:25:09

      > S'il y a au moins une réponse qui a été donnée, on trie
      > avec le timestamp de la dernière réponse, et sinon,
      > avec le timestamp du premier post.

      Une réponse et un post, c'est pareil (sauf qu'on ne va pas appeler "réponse" le 1er post d'un topic).

      Si il n'y a qu'un post dans le topic, le dernier est aussi le premier.

      Donc trier par timestamp (ou id) du dernier post est la bonne stratégie (avec un petit détour pour les topics en sticky...)

      Tous les forums marchent de la même façon : dans la table topics, il y une colonne "last_post_id" qui donne l'id du dernier post dans le topic (qui est aussi le premier si il y en a qu'un) et tu tries par (sticky, last_post_id DESC).

      Sinon, si tu as un tout petit forum et que tu aimes que ça rame beaucoup, tu peux ne pas le faire, et utiliser un truc comme ça (basé sur le GROUP BY non-standard de mysql) :

      SELECT ...
      FROM topics JOIN posts USING( topic_id )
      GROUP BY topic_id
      ORDER BY sticky DESC, max(post_id) DESC
      



      • Partager sur Facebook
      • Partager sur Twitter
        24 avril 2011 à 10:53:09

        Salut et merci de ta réponse !

        Je pense donc utiliser ta méthode en créant une colonne dans ma table sujets 'id_derniere_reponse'.
        Par contre, qu'est ce qu'un sticky ? C'est le nom donné aux post-its ?

        Dans la table, tu me conseilles d'insérer le 'id_derniere_reponse' à quel moment ? Lors du post de la réponse ? Et si je supprime le post en question ? Je mets l''id_derniere_reponse' de la précédente ?
        Merci ! :)
        • Partager sur Facebook
        • Partager sur Twitter
          24 avril 2011 à 11:16:30

          > qu'est ce qu'un sticky ? C'est le nom donné aux post-its ?

          Ouais.

          Si sticky est un tinyint qui vaut 1 pour un sticky et 0 pour un topic normal, mettre ORDER BY sticky DESC, last_post_id DESC met les sticky en haut...

          Si tu créé un index sur topics(forum_id, sticky, post_id) alors une requête du style "WHERE forum_id=xxx ORDER BY sticky DESC, last_post_id DESC" ne fera pas de tri du tout, la BDD se contente de parcourir l'index à l'envers, les entrées sont déjà triées dedans, donc c'est le plus rapide.

          Dans ce cas, l'intérêt principal de mettre un bash à Merise en dénormalisant (dénormaliser = mettre dans topics une colonne qui est en fait un doublon puisque tu pourrais la calculer aves une requête) est que tu peux poser un index sur la colonne en question et donc augmenter énormément les perfs.

          > tu me conseilles d'insérer le 'id_derniere_reponse'
          > à quel moment ?

          Le plus simple, c'est avec un trigger sur la table posts (et puis ça t'apprendra à faire des triggers !), ajoute un trigger ON DELETE aussi...

          -> BEFORE INSERT FOR EACH ROW EXECUTE (là tu mets last_post_id = NEW.post_id)
          -> AFTER DELETE FOR EACH ROW EXECUTE (là tu vérifies si tu as supprimé le dernier post, si non tu fais rien, si oui tu mets last_post_id = max(post_id) FROM posts WHERE topic_id = OLD.topic_id)

          Sinon tu peux le faire dans ton code php aussi si t'as pas envie de te cultiver :p... mais faut pas oublier.

          Tu peux en profiter pour tenir à jour les compteurs "nombre de posts dans le topic" aussi.

          L'avantage du trigger c'est que tu peux pas oublier. L'inconvénient c'est que quand tu supprimes un topic, le trigger ON DELETE sera exécuté une fois par post...
          • Partager sur Facebook
          • Partager sur Twitter
            24 avril 2011 à 11:36:34

            Ok, c'est noté, je vais feuilleter un peu le net, ça en fait des nouveautés !
            Merci de t'être donné du mal pour moi !

            [EDIT : Ah non en fait.. Petite question, si je fais ça avec l'id du message, qu'en est il pour les sujets ? Comment saura t il si l'id correspond à un sujet ou à une réponse ?
            • Partager sur Facebook
            • Partager sur Twitter
              24 avril 2011 à 12:01:20

              tu mets aussi dans la table topics une colonne "nombre de posts dans le topic"

              si y'en a qu'un c'est le post original, et le nombre de réponses est "nombre de posts dans le topic" - 1

              je ne comprends pas trop ta distinction entre "sujet" et "réponse"...
              • Partager sur Facebook
              • Partager sur Twitter
                24 avril 2011 à 12:04:30

                Eh bien en fait comme expliqué en premier post, j'ai deux tables.
                La première "sujets" qui contient tous les sujets et aussi le premier message, le sujet quoi.
                La deuxième "reponses" qui contient toutes les réponses.

                Mais lors du tri, si je stocke dans une colonne l'id du dernier post, ça concernera soit la réponse soit le sujet.. Comment les distinguer ? Encore une colonne avec 1 = sujet 2 = reponse ?

                Ne peut on pas faire un truc du genre if(id_derniere_reponse == 0) {id_derniere_reponse = timestamp_sujet} ?

                EDIT : Ou sinon, je stocke tout simplement le timestamp de la dernière réponse, comme ça j'adapterai depuis PHP ?
                • Partager sur Facebook
                • Partager sur Twitter
                  24 avril 2011 à 12:05:41

                  OK

                  Le premier message n'a rien à faire dans la table "sujets" puisque c'est un post, il doit donc être dans la table "posts"...

                  Dans la table "sujets" on met juste le titre du sujet, la date de création, etc... mais on ne met pas de posts...
                  • Partager sur Facebook
                  • Partager sur Twitter
                    24 avril 2011 à 12:06:25

                    Ouais, je sais, mais c'est mes tables qui sont mal organisées :|
                    Je dois tout refaire ? ^^'
                    • Partager sur Facebook
                    • Partager sur Twitter
                      24 avril 2011 à 12:08:23

                      Y a aussi la recherche : quand tu fais une recherche dans le forum, elle s'applique au texte des posts... si tu dois chercher dans 2 tables ça complique.

                      Donc oui (mais "tout refaire", non... tu en as pas pour très longtemps ;)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        24 avril 2011 à 12:09:56

                        Et moi qui étais content d'avoir fini mon forum :euh:
                        Bon, bah, je me lance :-

                        Merci ^^'

                        EDIT : Mon forum est remis sur pieds ! Avec la technique conseillée : les messages du premier post sont stockés dans la table des reponses.
                        Cependant, j'ai un nouveau soucis, moins embêtant je pense, pour la requête.
                        Le timestamp de la dernière réponse est stocké avec la réponse dans la table des réponses.
                        Ma requête a son FROM sur la table des sujets.
                        Si je fais un LEFT JOIN, la dernière réponse du sujet apparaît comme une réponse car il y a déjà une jointure avec la table des réponses notamment pour récupérer le timestamp du premier post.

                        Comment éviter svp cela ?

                        EDIT 2 : REPARE. J'avais oublié une condition dans mon WHERE.
                        Tout marche à merveille, je sais pas trop comment tant les dernières modifs du script m'ont embrouillé mais ça marche c'est l'essentiel :D A la prochaine et merci pour tout :)
                        • Partager sur Facebook
                        • Partager sur Twitter

                        ORDER BY et sous requête

                        × 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.
                        • Editeur
                        • Markdown