2010-09-03 5 views
7

Je possède ce tableau:Comment générer une arborescence à partir de ce jeu de résultats basé sur l'algorithme Tree Traversal?

CREATE TABLE `categories` (
    `id` int(11) NOT NULL auto_increment, 
    `category_id` int(11) default NULL, 
    `root_id` int(11) default NULL, 
    `name` varchar(100) collate utf8_unicode_ci NOT NULL, 
    `lft` int(11) NOT NULL, 
    `rht` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `category_id` (`category_id`), 
    KEY `lft` (`lft`,`rht`), 
    KEY `root_id` (`root_id`) 
) 

Sur la base de cette question: Getting a modified preorder tree traversal model (nested set) into a <ul>

La différence est que j'ai beaucoup d'arbres dans une table. Chaque ligne a une clé étrangère représentant son parent et son parent supérieur: category_id et root_id. J'ai aussi les champs de LFT et RHT basé sur cet exemple: http://articles.sitepoint.com/article/hierarchical-data-database/2

Sur la base de cette lignes:

INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14); 
INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3); 
INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 4, 9); 
INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 5, 6); 
INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 7, 8); 
INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 10, 11); 
INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 12, 13); 
INSERT INTO `categories` VALUES(8, NULL, NULL, 'Eletronics', 1, 14); 
INSERT INTO `categories` VALUES(9, 8, 8, 'Cell Phones', 2, 3); 
INSERT INTO `categories` VALUES(10, 8, 8, 'Computers', 4, 9); 
INSERT INTO `categories` VALUES(11, 10, 8, 'PC', 5, 6); 
INSERT INTO `categories` VALUES(12, 10, 8, 'MAC', 7, 8); 
INSERT INTO `categories` VALUES(13, 8, 8, 'Printers', 10, 11); 
INSERT INTO `categories` VALUES(14, 8, 8, 'Cameras', 12, 13); 

Comment puis-je construire une liste ordened représentant cet arbre?

Avec le soufflet sql:

SELECT c. * , (COUNT(p.id) -1) AS depth 
FROM `categorias` AS p 
CROSS JOIN categories AS c 
WHERE (
c.lft 
BETWEEN p.lft 
AND p.rht 
) 
GROUP BY c.id 
ORDER BY c.lft; 

J'ai obtenu ce résultat:

alt text

Comme vous pouvez le voir, je dois commander par ROOT_ID aussi, pour que je puisse générer le bon arbre.

De même, après avoir obtenu l'arbre, y a-t-il un moyen de commander chaque nœud par son nom?

Répondre

0

Je l'ai eu. Tout ce que vous avez à faire est de définir root_id pour les parents supérieurs, afin que vous puissiez ORDER BY correctement.

Avec la requête ci-dessous, je peux avoir des arbres separeted, et que l'arbre Mises à Jour que je travaille sur:

SELECT c . * , count(p.id) AS depth 
FROM `categories` c 
CROSS JOIN categories p 
WHERE (
c.lft 
BETWEEN p.lft 
AND p.rht 
) 
AND c.root_id = p.root_id 
GROUP BY c.id 
ORDER BY c.root_id, c.lft 
2

Comme vous pouvez le voir, j'ai besoin de commander par root_id aussi, afin que je puisse générer l'arbre correct.

Lors de la construction du modèle d'arbre imbriqué, ne jamais faire des doublons sur lft et rgt. En fait, vous devriez les déclarer uniques.

Dans votre modèle de données, les jeux pour la catégorie 1 et 8 se chevauchent. Dites, 1 à 14 sont utilisés à la fois pour les articles 1 et 8.

Remplacez-les par ces valeurs:

INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14); 
INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3); 
INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 4, 9); 
INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 5, 6); 
INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 7, 8); 
INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 10, 11); 
INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 12, 13); 
INSERT INTO `categories` VALUES(8, NULL, NULL, 'Eletronics', 15, 29); 
INSERT INTO `categories` VALUES(9, 8, 8, 'Cell Phones', 16, 17); 
INSERT INTO `categories` VALUES(10, 8, 8, 'Computers', 19, 24); 
INSERT INTO `categories` VALUES(11, 10, 8, 'PC', 20, 21); 
INSERT INTO `categories` VALUES(12, 10, 8, 'MAC', 22, 23); 
INSERT INTO `categories` VALUES(13, 8, 8, 'Printers', 25, 26); 
INSERT INTO `categories` VALUES(14, 8, 8, 'Cameras', 27, 28); 

Maintenant, vous n'avez pas à commander sur root_id.

De même, après avoir obtenu l'arborescence, existe-t-il un moyen de classer chaque nœud par son nom?

Pas facile, sauf si vous insérez les nœuds dans l'ordre des noms depuis le début. Frères et sœurs avec plus name devraient avoir une plus grande lft et rgt:

INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14); 
INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3); 
INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 4, 5); 
INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 6, 11); 
INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 7, 8); 
INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 9, 10); 
INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 12, 13); 

Un arbre imbriqué ne peut avoir un ordre implicite.

Il y a aussi une façon d'interroger la liste de contiguïté dans MySQL:

, cependant, vous devrez créer une colonne de commande supplémentaire unique si vous voulez commander sur quoi que ce soit d'autre de id.

Vous pouvez également lire cet article:

qui montre comment stocker et de requête ensembles plus efficacement imbriqués.

+0

Merci, je vais lire et essayer. Bien, je me demandais s'il n'y a pas un moyen de garder lft et rht répétés puisque j'ai un moyen de distinguer (root_id). J'ai déjà réalisé une requête avec quelque chose comme: WHERE root_id = 1 OU id = 1 ORDER BY lft pour obtenir l'un des arbres (mais pas tous). C'est vraiment la mauvaise façon? Aussi j'ai le root_id pour la référence en utilisant la méthode rebuild_tree() listée sur ce lien http://articles.sitepoint.com/article/hierarchical-data-database/3 Donc, tout fonctionne correctement sauf le SELECT pour les listes ordonnées. –

+0

Si je suis vos étapes, comment puis-je modifier la fonction rebuild_tree() pour reconstruire un seul arbre et pas tous? Depuis que je vais supprimer root_id? –

+0

Si vous séparez toujours les arbres (comme avec 'WHERE root_id = 1'), vous pouvez autoriser le chevauchement entre différents ensembles. Mais votre requête originale a mélangé deux arbres. Pour reconstruire un seul arbre, appelez simplement 'rebuild_tree (1)' ou 'rebuild_tree (8)', cela reconstruira seulement les arbres à partir de '1' ou' 8'. – Quassnoi

Questions connexes