我的数据库中有一个页面表,每个页面都有一个父页面如下:
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
答案 0 :(得分:5)
我认为你应该在你的表中添加一个字段,称为level并在其中存储节点的级别,然后按级别然后按父级对查询进行排序。
答案 1 :(得分: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)
EXPLAIN的输出:
+------+--------------------+--------------+--------+---------------+---------+---------+--------------------------+------+----------------+
| 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上添加了一个索引以提高性能。
答案 2 :(得分:3)
如果您可以控制表架构,则可能需要考虑使用嵌套集表示。 Mike Hillyer写了一篇关于此的文章:
答案 3 :(得分: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
就是它..
答案 4 :(得分:1)
唉。像这样涉及树的查询很烦人,一般来说,如果你希望它可以扩展到任意数量的级别,你不会用一个查询来完成它,你将使用一些在每个级别构建树。
答案 5 :(得分:0)
好吧,你总是可以在一个查询中获取它并在PHP中处理它。这可能是获得树的简单方法。