2009-08-15 7 views
3

J'ai une table de pages dans ma base de données, chaque page peut avoir un parent comme ci-dessous:requête MySQL à l'ordre par le parent puis l'enfant place

id   parent_id   title 
1    0     Home 
2    0     Sitemap 
3    0     Products 
4    3     Product 1 
5    3     Product 2 
6    4     Product 1 Review Page 

Quelle serait la meilleure requête MySQL pour sélectionner toutes les pages commandées par parent puis enfant puis enfant s'il y a plus d'un niveau, il y aura un maximum de trois niveaux. L'exemple ci-dessus produirait l'ordre désiré:

Home 
Sitemap 
Products 
    Product 1 
     Product 1 Review Page 
    Product 2 

Répondre

5

Je pense que vous devriez mettre un champ plus dans votre table, le niveau appelé et stocker dans ce niveau du nœud, et puis trier votre requête en fonction du niveau puis par parent.

1

Ugh. Les requêtes comme celles-ci impliquant des arbres sont agaçantes et généralement, si vous voulez qu'elles soient évolutives à un certain nombre de niveaux, vous ne le ferez pas avec une seule requête, vous en utiliserez quelques unes pour construire l'arbre à chaque niveau.

3

Si vous avez un certain contrôle sur le schéma de la table, vous pouvez envisager d'utiliser une représentation d'ensemble imbriquée à la place. Mike Hillyer a écrit un article sur ce point:

Managing Hierarchical Data in MySQL

0

Eh bien, vous pouvez toujours tout obtenir en une seule requête et le traiter en PHP. Ce serait probablement le moyen le plus simple d'obtenir un arbre.

+0

php est pas assez rapide comme sql! –

5

Si vous devez rester avec votre modèle, je suggère cette requête:

SELECT p.id, p.title, 
     (
     SELECT LPAD(parent.id, 5, '0') 
     FROM page parent 
     WHERE parent.id = p.id AND parent.parent_id = 0 

     UNION 

     SELECT CONCAT(LPAD(parent.id, 5, '0'), '.', LPAD(child.id, 5, '0')) 
     FROM page parent 
     INNER JOIN page child ON (parent.id = child.parent_id) 
     WHERE child.id = p.id AND parent.parent_id = 0 

     UNION 

     SELECT CONCAT(LPAD(parent.id, 5, '0'), '.', LPAD(child.id, 5, '0'), '.', LPAD(grandchild.id, 5, '0')) 
     FROM page parent 
     INNER JOIN page child ON (parent.id = child.parent_id) 
     INNER JOIN page grandchild ON (child.id = grandchild.parent_id) 
     WHERE grandchild.id = p.id AND parent.parent_id = 0 
     ) AS level 
FROM page p 
ORDER BY level; 

Exemple de jeu de résultats:

+-----+-------------------------+-------------------+ 
| id | title     | level    | 
+-----+-------------------------+-------------------+ 
| 1 | Home     | 00001    | 
| 2 | Sitemap     | 00002    | 
| 3 | Products    | 00003    | 
| 4 | Product 1    | 00003.00004  | 
| 6 | Product 1 Review Page 1 | 00003.00004.00006 | 
| 646 | Product 1 Review Page 2 | 00003.00004.00646 | 
| 5 | Product 2    | 00003.00005  | 
| 644 | Product 3    | 00003.00644  | 
| 645 | Product 4    | 00003.00645  | 
+-----+-------------------------+-------------------+ 
9 rows in set (0.01 sec) 

Sortie de EXPLIQUER:

+------+--------------------+--------------+--------+---------------+---------+---------+--------------------------+------+----------------+ 
| id | select_type  | table  | type | possible_keys | key  | key_len | ref      | rows | Extra   | 
+------+--------------------+--------------+--------+---------------+---------+---------+--------------------------+------+----------------+ 
| 1 | PRIMARY   | p   | ALL | NULL   | NULL | NULL | NULL      | 441 | Using filesort | 
| 2 | DEPENDENT SUBQUERY | parent  | eq_ref | PRIMARY,idx1 | PRIMARY | 4  | tmp.p.id     | 1 | Using where | 
| 3 | DEPENDENT UNION | child  | eq_ref | PRIMARY,idx1 | PRIMARY | 4  | tmp.p.id     | 1 |    | 
| 3 | DEPENDENT UNION | parent  | eq_ref | PRIMARY,idx1 | PRIMARY | 4  | tmp.child.parent_id  | 1 | Using where | 
| 4 | DEPENDENT UNION | grandchild | eq_ref | PRIMARY,idx1 | PRIMARY | 4  | tmp.p.id     | 1 |    | 
| 4 | DEPENDENT UNION | child  | eq_ref | PRIMARY,idx1 | PRIMARY | 4  | tmp.grandchild.parent_id | 1 |    | 
| 4 | DEPENDENT UNION | parent  | eq_ref | PRIMARY,idx1 | PRIMARY | 4  | tmp.child.parent_id  | 1 | Using where | 
| NULL | UNION RESULT  | <union2,3,4> | ALL | NULL   | NULL | NULL | NULL      | NULL |    | 
+------+--------------------+--------------+--------+---------------+---------+---------+--------------------------+------+----------------+ 
8 rows in set (0.00 sec) 

je cette disposition de table:

CREATE TABLE `page` (
    `id` int(11) NOT NULL, 
    `parent_id` int(11) NOT NULL, 
    `title` varchar(255) default NULL, 
    PRIMARY KEY (`id`), 
    KEY `idx1` (`parent_id`) 
); 

Notez que j'ai inclus un index sur parent_id pour améliorer les performances.

+0

Ceci est une excellente réponse. Très utile en effet, juste utilisé cette approche dans l'un de mes projets. Merci. –

+0

Cela ne fonctionne que pour 3 niveaux i.e jusqu'à petit-enfant, ci-dessous, il montre le niveau nul – Shahbaz

2

Travaillez plus intelligemment:

SELECT menu_name , CONCAT_WS('_', level3, level2, level1) as level FROM (SELECT 
t1.menu_name as menu_name , 
t3.sorting AS level3, 
t2.sorting AS level2, 
t1.sorting AS level1 
FROM 
en_menu_items as t1 
LEFT JOIN 
en_menu_items as t2 
on 
t1.parent_id = t2.id 
LEFT JOIN 
en_menu_items as t3 
on 
t2.parent_id = t3.id 
) as depth_table 
ORDER BY 
level 

qui est-il ..

Questions connexes