2011-02-28 63 views
2

也许最简单的方法来管理MySQL数据库中的分层数据是adjacency list model。这是,给每个节点父:在MySQL表中获取树路径

CREATE TABLE category(
category_id INT AUTO_INCREMENT PRIMARY KEY, 
name VARCHAR(20) NOT NULL, 
parent INT DEFAULT NULL); 

这是很容易获得的父节点,或者即使有一个最大树深度,您可以使用此得到整个树:

SELECT CONCAT_WS('/', `t3`.`name`, `t2`.`name`, `t1`.`name`) AS `path` 
FROM category AS t1 
LEFT JOIN category AS t2 ON t2.parent = t1.category_id 
LEFT JOIN category AS t3 ON t3.parent = t2.category_id 
LEFT JOIN category AS t4 ON t4.parent = t3.category_id 
WHERE t1.name = 'xxxxx'; 

这在很多情况下已经足够了,但是如何将这个解决方案概括为比3个节点更深的树?即您可能会有类似“电子/音频/发射器/ FM /摩托罗拉”的路径。

只有一个查询可能吗?

回答

2

中描述这里有一个简单的非递归存储过程,没有工作:

drop table if exists employees; 
create table employees 
(
emp_id smallint unsigned not null auto_increment primary key, 
name varchar(255) not null, 
boss_id smallint unsigned null, 
key (boss_id) 
) 
engine = innodb; 

insert into employees (name, boss_id) values 
('f00',null), 
    ('ali later',1), 
    ('megan fox',1), 
     ('jessica alba',3), 
     ('eva longoria',3), 
     ('keira knightley',5), 
      ('liv tyler',6), 
      ('sophie marceau',6); 


drop procedure if exists employees_hier; 

delimiter # 

create procedure employees_hier 
(
in p_emp_id smallint unsigned 
) 
begin 

declare v_done tinyint unsigned default(0); 
declare v_dpth smallint unsigned default(0); 

create temporary table hier(
boss_id smallint unsigned, 
emp_id smallint unsigned, 
depth smallint unsigned 
)engine = memory; 

insert into hier select boss_id, emp_id, v_dpth from employees where emp_id = p_emp_id; 

/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */ 

create temporary table emps engine=memory select * from hier; 

while not v_done do 

    if exists(select 1 from employees e inner join hier on e.boss_id = hier.emp_id and hier.depth = v_dpth) then 

     insert into hier select e.boss_id, e.emp_id, v_dpth + 1 
      from employees e inner join emps on e.boss_id = emps.emp_id and emps.depth = v_dpth; 

     set v_dpth = v_dpth + 1;    

     truncate table emps; 
     insert into emps select * from hier where depth = v_dpth; 

    else 
     set v_done = 1; 
    end if; 

end while; 

select 
e.emp_id, 
e.name as emp_name, 
p.emp_id as boss_emp_id, 
p.name as boss_name, 
hier.depth 
from 
hier 
inner join employees e on hier.emp_id = e.emp_id 
left outer join employees p on hier.boss_id = p.emp_id; 

drop temporary table if exists hier; 
drop temporary table if exists emps; 

end # 

delimiter ; 

-- call this sproc from your php 

call employees_hier(1); 
+0

Mhh ..只有一个查询不能完成任务,但它完成了这项工作。为了避免出现问题,是否应该锁定表格“员工”? – Ivan 2011-02-28 15:19:20

+0

只需一个电话 - 致电employees_hier(1),我会推荐innodb而不是myisam。 – 2011-02-28 18:43:04

+0

这是阿里·拉特...伟大的选择,顺便说一句:-) – 2011-03-18 16:25:15

0

正如那篇文章所解释的那样,您需要知道节点的深度以生成其路径,您可以通过为不同深度的节点生成单独的查询来执行此操作。这是嵌套集模型经常被优先选择的原因之一。

获取某个节点的路径从一组嵌套模式,改编自Managing Hierarchical Data in MySQL例如:

SELECT CONCAT(GROUP_CONCAT(parent.name 
          ORDER BY parent.lft 
          SEPARATOR '/'), 
       '/Motorola') 
    FROM nested_category AS node, 
     nested_category AS parent 
    WHERE node.lft BETWEEN parent.lft AND parent.rgt 
    AND node.name = 'Motorola' 
;