Partage
  • Partager sur Facebook
  • Partager sur Twitter

Ordonner les résultats d'une requête d'arbre intervallaire

Suite au super tuto de Talus

    6 avril 2011 à 19:40:18

    Bonjour à tous,

    Cette question concerne l'excellent tuto de Talus sur les arbres intervallaires :

    Voir ici

    J'ai une question à ce sujet, car je voudrais pouvoir donner à mes users la possibilité d'ordonner l'affichage des feuilles...(avec jquery et le glisser/déposer).

    C'est à dire que, pour reprendre le schéma, les feuilles du niveau 1 et les feuilles du niveau 2 G (sous la feuille 2-7) et 2 D (sous la feuille 12-17).
    J'ai donc introduit dans ma table une notion de poids avec une colonne supplémentaire.

    Ainsi, par exemple, les 4 feuilles du niveau 1, de haut en bas, auraient respectivement les poids 1, 2, 3 et 4.
    Les niveaux 2 gauche et droite auraient 1 et 2.
    Puis le user modifie les ordres et les poids pourraient devenir 4,1,2,3 au niveau 1, 2,1 au 2G et 1,2 au 2D.

    Oui...mais, comme il faut ORDER BY gauche si on veut respecter la hiérarchie lors de l'affichage, ça ne va plus avec la notion de "poids"... Et à l'inverse, si on ORDER BY poids, on fiche en l'air la hiérarchie.
    Quant au ORDER BY left, poids, évidemment, il donne le même résultat que BY gauche.

    Auriez-vous une idée quant à l'introduction de cette notion de "poids" dans l'arbre ?
    Modifier les bornes à chaque variante me semble difficile...
    D'avance, Je vous remercie.

    EDIT :
    Bon, pour illustrer ma question voici une vue de ma table :
    Image utilisateur

    Prenons l'exemple du sous-arbre "Navigation" : et bien je voudrais que le user puisse décider que "Navigation dans les articles" - et ses enfants - s'affichent avant "Navigation dans le plan du site" qui n'a pas d'enfant...ou l'inverse. Et il pourrait aussi décider de l'ordre d'affichage des enfants de "Navigation dans les articles" : "Avec Firefox" s'afficherait avant "Avec Internet Explorer"...ou l'inverse.

    :-°
    • Partager sur Facebook
    • Partager sur Twitter
      7 avril 2011 à 11:05:49

      Hello,

      Ce que je pense que tu puisses faire, c'est l'utilisation d'une deuxième table, qui lie le poids selon l'utilisateur. Ensuite, tu sélectionnes donc bien tous les enfants / éléments à sélectionner, puis tu peux alors trier sur ce même résultat suivant ton poids... ?
      • Partager sur Facebook
      • Partager sur Twitter
      Mon profil Github - Zeste de Savoir, pour la beauté du zeste
        7 avril 2011 à 11:25:22

        Bonjour et merci de ta réponse,

        J'ai dû mal m'expliquer sur la notion des "users".
        Il s'agit en fait d'un administrateur qui va décider d'afficher telle catégorie / sous catégorie de FAQ avant une autre.
        C'est un mono-utilisateur, donc je n'ai pas à prendre en considération les choix d'un user 1,ou 2..

        Je veux simplement que lui, cet admin, puisse décider de l'ordre d'affichage par niveau.
        Tu vois ?

        :)

        Je n'arrive pas à lire la table à la fois en profondeur - pour la cohésion de l'affichage, ça c'est le ORDER BY lft - ET en "latéral" pour les ordres d'affichage / niveau...
        • Partager sur Facebook
        • Partager sur Twitter
          7 avril 2011 à 13:09:44

          L'arbre est déjà ordonné, il te suffit de déplacer les sous-arbres/feuilles pour ordonner différemment.
          • Partager sur Facebook
          • Partager sur Twitter
            7 avril 2011 à 14:34:30

            Bonjour et merci de ta réponse.

            Cependant, je ne te comprends pas quand tu dis "l'arbre est déjà ordonné".
            Ordonné comment ?
            Si tu veux que ton arbre s'affiche correctement sur la page, tu dois faire un ORDER BY gauche, de sorte que, en prenant le schéma de Talus, les bornes gauches 1, 2 et 3 s'affichent les unes sous les autres, sinon ça n'a pas d'intérêt.
            Or avec cet ordre, on lit l'arbre en profondeur, puis on "remonte" au niveau 1, bornes 7, 8, etc..
            Comment, dans ces conditions, peux-tu faire pour décider que les bornes G 8, 10 ou 12 seront lues avant la 2 ?

            Dans la logique, on lit "verticalement"...et là, il faudrait lire "horizontalement".
            Pour résumer, l'arbre est lu dans son ordre naturel d'insertion des feuilles, et moi, je voudrais pouvoir changer ça.

            • Partager sur Facebook
            • Partager sur Twitter
              7 avril 2011 à 14:54:38

              Rien ne t'empêche de déplacer les feuilles/arbres (= changer leurs bornes), ce qui changera l'ordre.
              • Partager sur Facebook
              • Partager sur Twitter
                7 avril 2011 à 15:04:58

                ah...là ça commence à me parler...Mais ou là là ma tête...

                Alors gardons l'arbre de Talus.
                Et nommons les feuilles pour plus de commodité :

                Au niveau 1, de bas en haut, les feuilles seraient A, B, C et D - A et D étant des nœuds.
                Si je veux que l'arbre D s'affiche avant l'arbre A, il "suffirait" donc que D ait les bornes 2 à 7 de A, et A les bornes 12 à 17 de D ?

                o_O

                Et comment ferais-tu cela ?
                Une piste ?
                • Partager sur Facebook
                • Partager sur Twitter
                  7 avril 2011 à 15:31:38

                  Déplacer une feuille sans changer son parent est facile, suffit d'inverser les bornes respectives. Déplacer un sous-arbre est beaucoup moins drôle.
                  * tu sors A de l'arbre, en lui mettant des bornes négatives par exemple.
                  * tu bouches le trou laissé par A.
                  * là ou était A, tu ouvres un trou suffisant pour y mettre D.
                  * tu met à jour les bornes de D.
                  * tu bouches le trou laissé par D.
                  * là ou était D, tu ouvres un trou suffisant pour y mettre A.
                  * tu mets à jour les bornes de A.

                  On peut éviter certaines opérations en étant malin et en redimensionnant les trous au lieu de les refermer, ce qui évite de devoir en rouvrir.

                  Et ici un article qui donne une procédure stockée pour faire cela : http://blog.developpez.com/sqlpro/p722 [...] ure-de-depla/
                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 avril 2011 à 15:49:34

                    :'(

                    Alors là, c'est l'usine à gaz totale !
                    J'ai lu l'article de F.Brouard, mais ça dépasse mes compétences de environ 25 000 kilomètres.
                    C'est quel langage, ça ?
                    Ça peut se faire en php / mysql ce truc hébreu ?

                    • Partager sur Facebook
                    • Partager sur Twitter
                      7 avril 2011 à 16:01:07

                      C'est long mais ça n'est pas très compliqué. un select pour avoir les bornes de deux sous-arbres et quelques updates pour déplacer les sous-arbres/boucher les trous/faire les trous.
                      C'est du PL/SQL à la sauce SQL server, grosso modo du SQL adouci de structures de contrôles (condition, goto, etc.) et oui on peut bien sûr le faire en PHP et SQL.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        7 avril 2011 à 16:13:09

                        Citation : Haku


                        C'est long mais ça n'est pas très compliqué. un select pour avoir les bornes de deux sous-arbres et quelques updates pour déplacer les sous-arbres/boucher les trous/faire les trous



                        Ah bon, ouf, j'ai eu peur... :lol:

                        Mais avant que je jette tous mes neurones sur le clavier ou que je me pende avec le fil de la souris, je reprends l'intro de F.Brouard :

                        Citation : F.Brouard


                        Cette procédure exemple (sous forme de primitive) permet de déplacer un sous arbre en le faisant devenir un fils ainé ou cadet, un grand frère ou un petit frère et même un père par rapport à l'élément ciblé.



                        Dans mon cas, ce serait intervertir deux frères et leur éventuelle marmaille...
                        Euh...c'est pas un peu plus simple ?
                        :euh:
                        • Partager sur Facebook
                        • Partager sur Twitter
                          7 avril 2011 à 16:30:06

                          Là, tout est géré. :p
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Mon profil Github - Zeste de Savoir, pour la beauté du zeste
                            7 avril 2011 à 17:44:34

                            Oui, la procédure donnée par F. Brouard fait bien plus que ce que tu demandes. Juste pouvoir intervertir des frères et changer le parent d'un sous-arbre, c'est généralement suffisant. Et tu n'as pas à tout faire en une procédure, tu peux très bien découper ça en plusieurs petites fonctions.
                            • Partager sur Facebook
                            • Partager sur Twitter
                              7 avril 2011 à 18:30:59

                              Oui, mais je capte pas trop la notion de "grand frère" / "petit frère", alors question : si je fais passer en premier un nœud par rapport à une feuille, il devient "grand frère" ? c'est ça la notion ?
                              Dans le schéma de Talus, si je veux intervertir D (noeud) et C (feuille), D devient grand frère de C ?

                              Et aussi : qu'est ce que c'est cette requête ?

                              SELECT @bgp = lft, @bdp = rgt
                                        FROM table  
                                        WHERE id_pere = '3'
                              


                              Dans phpMyAdmin, ça retourne NULL.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                7 avril 2011 à 18:41:46

                                Oui, c'est ça. Plus l'élément est "à gauche" (= à la borne gauche la plus petite), plus il est "âgé" dans la famille. Un grand frère a une borne gauche inférieure à son petit frère, le fils ainé est l'élément qui a la plus petite borne gauche dans un niveau d'un sous-arbre, etc.

                                (j'ai pas regardé l'article dans le détail, possible que F. Brouard fasse l'inverse et que l'élément le plus à droite soit le plus âgé)
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  7 avril 2011 à 19:42:37

                                  Ben c'est quand même bien casse-tête...

                                  En me basant sur l'article de Brouard, j'ai fait :

                                  for ($i = 0; $i < count ( $sortlist ); $i++) 
                                  	{
                                  			
                                  	$recup = mysql_query("SELECT nom, id_pere, lft, rgt FROM jld_faq_cat WHERE id = '".$sortlist[$i]."'");
                                  	$row = mysql_fetch_assoc($recup);
                                  	$id_pere = $row['id_pere'];
                                  	$max_rgt = max_right($sortlist[$i]); // fonction qui récup la borne droite maxi
                                  	$delta = $row['rgt'] - $row['lft'] + 1;
                                   		  
                                  	  mysql_query("UPDATE jld_faq_cat 
                                            SET lft = lft + ".$delta.", 
                                                rgt = rgt + ".$delta."
                                            WHERE lft >= '".$row['lft']."' AND rgt <= '".$row['rgt']."'") or die(mysql_error());
                                  		  
                                  		  
                                  	  mysql_query("UPDATE jld_faq_cat 
                                            SET rgt = rgt - ".$delta." 
                                            WHERE rgt > '".$row['rgt']."' AND lft <= '".$max_rgt."'") or die(mysql_error());
                                  			
                                  	  mysql_query("UPDATE jld_faq_cat 
                                            SET lft = lft - '".$delta."' 
                                            WHERE lft > '".$row['rgt']."' AND lft < '".$max_rgt."'") or die(mysql_error());
                                  		  
                                  	  $rec = mysql_query("SELECT lft, rgt
                                            FROM jld_faq_cat  
                                            WHERE id_pere = '".$row['id_pere']."'") or die(mysql_error());
                                  		  $sel = mysql_fetch_row($rec);
                                  		  
                                  	  mysql_query("UPDATE jld_faq_cat 
                                            SET rgt = lft + 2 
                                            WHERE rgt >= '".$sel[1]."' AND rgt <= ".$max_rgt) or die(mysql_error()); 
                                  		  
                                  	  mysql_query("UPDATE jld_faq_cat 
                                            SET lft = rgt + 2 
                                            WHERE lft >= '".$sel[0]."' AND rgt < ".$max_rgt) or die(mysql_error());  
                                  		  
                                  	  mysql_query("UPDATE jld_faq_cat 
                                            SET lft = '".$sel[0]."', 
                                            rgt = '".$sel[0]."' + 1
                                            WHERE id = '".$sortlist[$i]."'") or die(mysql_error()); 
                                  }
                                  


                                  Et ça c'est la formule "grand frère". La boucle for affiche un tableau avec les ID des catégories ordonnées. Elle comporte autant de valeurs que ce que le niveau compte de feuilles. Ainsi, pour le niveau 1 de Talus, en supposant que les bornes - selon son schéma - soient :

                                  - D
                                  - C
                                  - B
                                  - A

                                  et que nous voulions monter A d'un "cran", la boucle serait :

                                  array(
                                  0=>D,
                                  1=>C,
                                  2=>A,
                                  3=>B)
                                  


                                  Résultat de la requête ci-dessus : un joli foutoir dans la table.
                                  Décourageant...
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    8 avril 2011 à 14:05:06

                                    Basiquement, l'idée d'un déplacement de noeud est la suivante : "supprimer" le noeud à déplacer (sans toutes fois véritablement le supprimer, d'où l'idée de le mettre dans des bornes négatives), puis "l'insérer" où tu veux l'insérer (soit ici à droite de C)...
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Mon profil Github - Zeste de Savoir, pour la beauté du zeste
                                      8 avril 2011 à 14:12:43

                                      Bonjour Talus,

                                      Je ne comprends pas la notion de "le supprimer sans le supprimer"...et des bornes négatives, et ensuite l'insérer...alors qu'il n'est pas supprimé.
                                      Désolé si je te parais un peu mou du cerveau.
                                      Tu peux mettre un petit exemple, ce serait cool.
                                      Merci d'avance.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        8 avril 2011 à 15:22:01

                                        En gros, tu dois retirer le noeud à déplacer de l'arbre. Mais pour le conserver (lui et ses données), tu vas pas vraiment le supprimer... Donc, tu le mets là ou tu es sur que ca n'entrera pas en collision avec quoique ce soit (d'où la mise en borne négative : le truc, c'est de retrancher la borne droite de ton noeud à toutes les autres bornes de ton noeud (y compris ses enfants)). Une fois le trou rebouché, tu peux alors réinsérer le noeud (en mettant donc les bornes correctes après avoir ouvert un trou) où tu le souhaites...
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Mon profil Github - Zeste de Savoir, pour la beauté du zeste
                                          8 avril 2011 à 16:39:12

                                          Ok, ce qui signifie, ne serait-ce que dans l'exemple de ton schéma, avec 2 noeuds et 2 feuilles au niveau 1 et la boucle for qui va donc tourner 4 fois...4 manips comme celle que tu viens de décrire ?
                                          Oula ! me demande si je ne vais pas revenir au récursif, tout compte fait...
                                          :-°

                                          En fait, l'intervallaire c'est bien si on affiche dans l'ordre d'insertion,mais si on décide de modifier cet ordre, ça devient chaud...
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            8 avril 2011 à 18:44:36

                                            Pourquoi faire une boucle ? Changer l'ordre des éléments, t'es pas censé le faire tout le temps (où 15 fois d'un coup)...
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Mon profil Github - Zeste de Savoir, pour la beauté du zeste
                                              8 avril 2011 à 19:08:52

                                              Ben tu sais, c'est une FAQ...donc au fur et à mesure que les questions viennent, l'admin va être amené à créer des nouvelle catégories, les déplacer, en intercaler de nouvelles selon ce qu'il pensera être cohérent.
                                              Mais je suis quand même déçu parce que j'ai bien l'intervallaire...
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                8 avril 2011 à 20:36:03

                                                Peut-être, mais il ne le fera pas 15 fois par heures ! Une fois les ajouts faits, il n'y aura à priori pas de modifications.

                                                De plus, il est vrai que ce n'est peut-être pas des plus adaptés ici la RI (si il n'y a qu'une profondeur)...
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Mon profil Github - Zeste de Savoir, pour la beauté du zeste

                                                Ordonner les résultats d'une requête d'arbre intervallaire

                                                × 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