2009-08-15 65 views
3

我有我的数据库页表,每个页面可以有如下父:MySQL查询由家长命令,然后孩子放在

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 

什么是最好的MySQL查询选择下令所有页面如果有多于一个等级,那么由父母再儿童再再等一次,最多会有三个等级。上面的例子会产生所需的顺序:

Home 
Sitemap 
Products 
    Product 1 
     Product 1 Review Page 
    Product 2 

回答

5

我想你应该多一个字段,你的表,称为水平和存储在其中的节点的级别,然后排序您的级别查询然后通过家长。

1

呃。像这样的涉及树的查询很烦人,一般来说,如果你希望它可以扩展到任何级别,你不会用一个查询来完成它,你会在每个级别上使用一些构建树。

0

那么,你总是可以在一个查询中得到它,并在PHP中处理它。这可能是获得树的最简单的方法。

+0

PHP是不够快如SQL! – 2018-03-06 14:38:45

5

如果你必须坚持你的模型,我建议这个查询:

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; 

结果集的例子:

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

的输出讲解:

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

我用此表布局:

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

请注意,我在parent_id中包含一个索引以提高性能。

+0

这是一个很好的答案。确实非常有用,只是在我的一个项目中使用了这种方法。谢谢。 – 2013-05-10 09:33:11

+0

这只适用于3级,即直到孙子,在它下面显示为零级 – Shahbaz 2016-07-15 10:16:04

2

工作更聪明而不是更辛苦:

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 

是吧..