相當簡單單的呼叫解決方案。建議避免像鼠疫這樣的嵌套集 - 最好留在教室裏!
所有你需要做的就是從你的php中調用這些存儲過程之一!
3210
Simples - 希望它幫助:)
示例結果
call menus_hier_downward(1);
+---------+-----------+-----------+------------------+-------+
| menu_id | menu_name | parent_id | parent_menu_name | depth |
+---------+-----------+-----------+------------------+-------+
| 1 | File | NULL | NULL | 0 |
| 2 | New | 1 | File | 1 |
| 3 | Document | 2 | New | 2 |
| 4 | Image | 2 | New | 2 |
+---------+-----------+-----------+------------------+-------+
4 rows in set (0.00 sec)
call menus_hier_upward(3);
+---------+-----------+-----------+------------------+-------+
| menu_id | menu_name | parent_id | parent_menu_name | depth |
+---------+-----------+-----------+------------------+-------+
| 3 | Document | 2 | New | 1 |
| 2 | New | 1 | File | 2 |
| 1 | File | NULL | NULL | 3 |
+---------+-----------+-----------+------------------+-------+
3 rows in set (0.00 sec)
我提供你兩個示例存儲過程。一個向下工作。全腳本如下:
表實施例
drop table if exists menus;
create table menus
(
menu_id smallint unsigned not null auto_increment primary key,
name varchar(255) not null,
parent_id smallint unsigned null,
key (parent_id)
)
engine = innodb;
insert into menus (name, parent_id) values
('File',null),
('New',1),
('Document',2),
('Image',2),
('Edit',null),
('Copy',5),
('Paste',5);
向下存儲過程
drop procedure if exists menus_hier_downward;
delimiter #
create procedure menus_hier_downward
(
in p_menu_id smallint unsigned
)
begin
declare v_done tinyint unsigned default(0);
declare v_dpth smallint unsigned default(0);
create temporary table hier(
parent_id smallint unsigned,
menu_id smallint unsigned,
depth smallint unsigned
)engine = memory;
insert into hier select parent_id, menu_id, v_dpth from menus where menu_id = p_menu_id;
/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
create temporary table tmp engine=memory select * from hier;
while not v_done do
if exists(select 1 from menus m inner join hier on m.parent_id = hier.menu_id and hier.depth = v_dpth) then
insert into hier select m.parent_id, m.menu_id, v_dpth + 1
from menus m inner join tmp on m.parent_id = tmp.menu_id and tmp.depth = v_dpth;
set v_dpth = v_dpth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = v_dpth;
else
set v_done = 1;
end if;
end while;
select
m.menu_id,
m.name as menu_name,
p.menu_id as parent_id,
p.name as parent_menu_name,
hier.depth
from
hier
inner join menus m on hier.menu_id = m.menu_id
left outer join menus p on hier.parent_id = p.menu_id;
drop temporary table if exists hier;
drop temporary table if exists tmp;
end #
delimiter ;
向上存儲過程
drop procedure if exists menus_hier_upward;
delimiter #
create procedure menus_hier_upward
(
in p_menu_id smallint unsigned
)
begin
declare v_done tinyint unsigned default(0);
declare v_dpth smallint unsigned default(0);
create temporary table hier(
parent_id smallint unsigned,
menu_id smallint unsigned,
depth smallint unsigned
)engine = memory;
insert into hier select menu_id, null, v_dpth from menus where menu_id = p_menu_id;
/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
create temporary table tmp engine=memory select * from hier;
while not v_done do
if exists(select 1 from menus m inner join hier on m.menu_id = hier.parent_id and hier.depth = v_dpth) then
insert into hier select m.parent_id, m.menu_id, v_dpth + 1
from menus m inner join tmp on m.menu_id = tmp.parent_id and tmp.depth = v_dpth;
set v_dpth = v_dpth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = v_dpth;
else
set v_done = 1;
end if;
end while;
select
m.menu_id,
m.name as menu_name,
p.menu_id as parent_id,
p.name as parent_menu_name,
hier.depth
from
hier
inner join menus m on hier.menu_id = m.menu_id
left outer join menus p on hier.parent_id = p.menu_id;
drop temporary table if exists hier;
drop temporary table if exists tmp;
end #
delimiter ;
「更有效的方式」 - 這是一個非常討論性的短語。在通常的樹形修改中,NS性能較差**。 – zerkms 2011-03-07 04:22:58
zerkms是正確的,但如果它不需要經常修改,那麼它可能是答案。 – 2011-03-07 04:28:01
有趣的文章,謝謝 – Simon 2011-03-07 04:45:59