2010-09-03 4 views
7

Ho questa tabella:Come generare una vista ad albero da questo set di risultati basato su Algoritmo dell'albero trasversale?

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`) 
) 

Sulla base di questa domanda: Getting a modified preorder tree traversal model (nested set) into a <ul>

La differenza è che ho molti alberi in una tabella. Ogni riga ha una chiave esterna che rappresenta il suo genitore e il suo genitore principale: category_id e root_id. Anche io ho i campi LFT e RHT sulla base di questo esempio: http://articles.sitepoint.com/article/hierarchical-data-database/2

Sulla base di questo file:

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); 

Come posso costruire una lista ordened che rappresenta l'albero?

Con il muggito 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; 

ho ottenuto questo risultato:

alt text

Come potete vedere, ho bisogno di ordinare per root_id troppo, in modo che possa generare la corretta albero.

Inoltre, dopo aver ottenuto l'albero, c'è un modo per ordinare ciascun nodo per nome?

risposta

0

Ho capito.

Tutto ciò che devi fare è impostare root_id anche ai top parents, in modo che tu possa ORDER BY correttamente.

Con la query soffietto posso avere separeted alberi, e uptade solo l'albero che sto lavorando su:

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

Come potete vedere, ho bisogno di ordinare anche da root_id, in modo che io possa generare l'albero corretto.

Quando si costruisce il modello ad albero nidificato, mai fare i duplicati su lft e rgt. In effetti, dovresti dichiararli unici.

Nel proprio modello di dati, i set per la categoria 1 e 8 si sovrappongono. Dì, 1 a 14 vengono utilizzati sia per gli articoli 1 e 8.

Sostituirli con questi valori:

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); 

Ora non c'è bisogno di ordinare on root_id.

Inoltre, dopo aver ottenuto l'albero, c'è un modo per ordinare ciascun nodo per nome?

Nessun modo semplice, a meno che non si inseriscano i nodi nell'ordine del nome dall'inizio. Fratelli con maggiore name dovrebbero avere una maggiore lft e 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 albero nidificato può avere un solo ordine implicito.

V'è anche un modo per interrogare lista di adiacenza in MySQL:

, tuttavia, sarà necessario creare una colonna ordinamento unico supplementare se volete ordinare su qualsiasi altra cosa di id.

Si consiglia inoltre di leggere questo articolo:

che mostra come memorizzare e query nidificate set in modo più efficiente.

+0

Grazie, mi leggerà questo e cercare. Sebbene, mi stavo chiedendo se non c'è un modo per mantenere ripetuto lft e rht poiché ho un modo di distinguere (root_id). Ho già raggiunto una query con qualcosa del tipo: WHERE root_id = 1 O id = 1 ORDINE DI lft per ottenere uno degli alberi (ma non tutti). Questo è davvero il modo sbagliato? Inoltre ho root_id come riferimento quando uso il metodo rebuild_tree() elencato su questo link http://articles.sitepoint.com/article/hierarchical-data-database/3 Quindi, tutto funziona correttamente eccetto il SELECT per gli elenchi ordinati. –

+0

Se seguo i tuoi passi, come posso cambiare la funzione rebuild_tree() per ricostruire solo un albero e non tutti? Dal momento che rimuoveremo root_id? –

+0

Se si separano sempre gli alberi (come con 'WHERE root_id = 1') è OK consentire la sovrapposizione tra diversi set. Ma la tua query originale ha mescolato due alberi. Per ricostruire solo un albero, chiama semplicemente 'rebuild_tree (1)' o 'rebuild_tree (8)', questo ricostruirà solo gli alberi a partire da '1' o' 8'. – Quassnoi