Aller au contenu

[EDIT] Requête SQL - hièrarchie - WHILE.


Sujets conseillés

Posté (modifié)

Bonsoir,

je souhaiterais créer une requête SQL capable de remonter une hièrarchie.

Donc obtenir chaque name précédant "Man" (voir informations ci-dessous).

Ce qui donnerait : Logistique -> Camions -> Man.

Je pensais créer un WHILE : remonter un niveau tant que "lvl" ne vaut pas "0".

Mais impossible d'écrire cette requête moi-même.

Merci de m'aider ou de m'indiquer une meilleure solution (autre qu'un while PHPique couplé à plusieurs requêtes).

// Informations :

[id] [lvl] [name]

1 0 Personnel

2 1 Mécanicien

3 1 Peintre

4 0 Logistique

5 4 Voitures

6 4 Camions

7 6 Man

Ce qui donnerait (type menu) :

Personnel.

-Mécanicien.

-Peintre.

Logistique.

-Voitures.

-Camions.

--Man.

N'hésitez pas à poser une question si cela vous semble confus.

Je suis vraiment bloqué là. :(

Chaque catégorie à donc une catégorie-mère représentée par [lvl].

[lvl] 0 indique que l'on arrive à la catégorie racine.

Je fourni au script un id de catégorie (p.e : 7) et il doit remonter jusqu'a la catégorie racine (en sélectionnant le nom de chaque catégorie-mère).

Il doit donc trouver :

0 -> 4 -> 6 -> 7.

Racine -> Logistique -> Camions -> Man.

Il y a quelques temps de cela j'utilisais un while() & effectuait plusieurs requêtes

Très vaguement :

$cat = 7;

while($cat!=0){

$resultat = query(SELECT name, topcat FROM categories WHERE id='$cat');

$cat = resultat['topcat'];

echo resultat['name'].' -> ';

}

Mais je préferais que cela se fasse du côté de MySQL.

Merci beaucoup.

Modifié par VidaNada
Posté (modifié)

CREATE PROCEDURE faireunwhile()
BEGIN DECLARE lvl1 INT DEFAULT 7;
WHILE lvl1>0 DO
SELECT name FROM categories WHERE lvl=lvl1;
SET lvl1=lvl1-1;
END WHILE;
END

Je n'ai pas testé.

J'apprenais ça au moment où je lisais ton post, et je me suis dit que ça serait une bonne idée de m'entrainer comme ça :)

J'espère que je n'ai pas trop de fautes, et désolé si ça marche mal...

Modifié par Théo B.
Posté

Merci beaucoup de te pencher sur mon problème, mais en essayant ton code, je suis tombé face à l'évidence même : les procédures sont apparues avec MySQL 5. :(

Ce serait donc :

_MySQL4 en traitant ceci avec PHP : plus lourd,

_MySQL5 : moins répandu et gain minime ?

Quel est votre avis ?

Posté (modifié)

Bonsoir,

sans répondre à ta question pour autant, la gestion algorithmique d'arbres n'est pas "efficace" (pour autant que ta structure soit modifiée moins de fois quelle n'est affichée) si tu utilises le modèle adjacent (parent->enfant) car tu utiliseras de la récursivité pour afficher ton arbre ou créer un breadcrumbs string (Catégorie > Sous-catégorie > Sous-sous catégorie > ...).

Personnellement j'utilise un arbre suivant un modèle de "Nested sets", qui est plus lourd à gérer lors de la mise à jour de la structure, mais moins lourd à parcourir.

J'en avais parlé sur ce fil : http://www.webmaster-hub.com/index.php?showtopic=13620

La classes PHP a déjà été écrite en partie (je l'ai crée en me basant sur cette "librairie" de fonction), j'y ai rajouté 2-3 fonctions et amélioré d'autres. A toi de voir si tu veux l'utiliser.

Concerant ton problème, je disais que tu devrais utiliser la récursivité. Le problème c'est que chaque enfant devrait être lié à un parent, spécifier le niveau (lvl) ne suffit pas... je m'explique :

Niveau 1

-Niveau 1.1

-Niveau 1.2

Niveau 2

-Niveau 2.1

Dans ce cas, comment sais tu dans ta table, que Niveau 2.1 appartient à Niveau 2 et non à Niveau 1.

Si tu compte sur l'rdre d'entrée des éléments dans la table, il faut vite oublier, le but de stocker de telles données dans une table est de pouvoir les modfier suivant, donc l'orde va changer très vite ;)

Le modèle adjacent se compose ainsi.

Table :

id  idparent  name
1  0  Racine
2  1  Niveau 1
3  2  Niveau 1.1
4  2  Niveau 1.2
5  1  Niveau 2
6  5  Niveau 2.1

Et éventuellement un champ "lvl" que tu metterais à jour toi-même.

Ainsi chaque "catégorie" a un parent, ensuite il faut utiliser la récursivité pour remonter dans la liste, par exemple :

function getPath($node) {
 // Recherche du parent
 $result = mysql_query("SELECT * FROM mytable WHERE id=".$node);
 if(mysql_num_rows($result) > 0) {
   $path = array();
   $parent = mysql_fetch_array($result);
   // Sommes-nous arrivés à la racine ?
   if($parent['idparent'] != 0) {
     $path[] = $parent['name'];
     $path = array_merge(getPath($parent['idparent']), $path);
   }
 }
 return $path;
}

La récusivité commence à cette ligne : $path = array_merge(getPath($parent['idparent']), $path);

On appelle la fonction qu'on est en train de créer à l'intérieur de celle-ci, le leur cas ou ces appels successif cesseront sera lorsque nous aurons atteint la racine (et également lorsqu'aucun résultat n'est trouvé dans al table, par sécurité).

Cette technique représente des inconvénient dans le cadre de grosses structures hiérarchiques cela représente beaucoup d'appel, jusque pour afficher un chemin ou même laa structure complète (c'est le meme principe). Et surtout lorsqu'on n'est pas à l'aise avec la récusivité, il peut se produire des problèmes de ressources en cas de boucle infinie (par exemple lorsqu'on test ;) ) car la fonction est chargé en mémoire à chaque fois qu'elle est appellée. En plus il y a une requête sur la base de donnée pour chaque noeud parcouru lors de la récursion.

Tu trouveras plus d'aide sur le modèle adjacent dans cet article (en anglais, désolé) : http://www.sitepoint.com/article/hierarchical-data-database

Bonne chance !

Modifié par TheRec
Posté

Ah d'accord, j'avais compris que "lvl" indiquait le niveau du noeud dans la hiérarchie ;) Mais après relecture c'est vrai, il correspond à idparent de mon exemple, pardon pour la confusion !

Posté (modifié)

Je vais conserver mon script puisqu'il fait exactement ce qui est nécessaire : analyse, mise en cache, vérification. Mais je vais ajouter quelques fonctionnalités comme le "niveau" des menus. :)

Le problème n'étant pas d'afficher le contenu, mais de limiter la requête SQL afin de gagner un peu de temps.

Le menu est mis en cache, mais l'endroit où se trouve l'utilisateur (Racine -> Logistique -> Camions -> Man.) devait être dynamique, il sera également caché afin d'éviter de charger toute la hièrarchie pour 4 catégories.

Merci. 1H45..:(

Modifié par VidaNada
Posté (modifié)

J'utilise depuis plusieurs années la même techno d'arbre hierarchique que Therec pour des nomenclatures de produits à n-niveaux, ou des arbres hiérarchiques pour décrire des procéssus divers.

En ce qui me concerne c'est sur procédures stockées SQL server, les algo sont assez connus (pour Oracle en tout cas, mais je ne me rappelle plus où j'avais trouvé mes sources)

L'article cité par Therec apporte une solution SQL très semblable

sinon tu peux me MP si tu souhaites mon code SQL

bon courage

Modifié par robinsonvendredi
Posté

Merci mais je vais sans doute conserver mon script, surement moins bien codé mais clair dans mon esprit. :D

Le problème étant toujours de limiter le nombre de requête, mais vu que la page sera "caché", ce n'est pas trop problématique.

Veuillez vous connecter pour commenter

Vous pourrez laisser un commentaire après vous êtes connecté.



Connectez-vous maintenant
×
×
  • Créer...