Я предпочитаю сделать один вызов в базу данных и вернуть дерево / поддерево, так как это намного эффективнее и сохраняет код вашего приложения чистым.
Ниже приведен пример для обзора, который может вас заинтересовать:
полный скрипт здесь: http://paste.pocoo.org/show/274386/
-- TABLES
drop table if exists trainer;
create table trainer
(
trainer_id smallint unsigned not null auto_increment primary key,
name varchar(255) not null
)
engine=innodb;
drop table if exists schedule;
create table schedule
(
sched_id smallint unsigned not null auto_increment primary key,
trainer_id smallint unsigned null,
name varchar(255) not null,
parent_sched_id smallint unsigned null,
key schedule_parent_idx(parent_sched_id),
key schedule_trainer_idx(trainer_id)
)
engine=innodb;
-- STORED PROCEDURES
drop procedure if exists schedule_hier;
delimiter #
create procedure schedule_hier
(
in p_sched_id smallint unsigned
)
begin
declare v_done tinyint unsigned default 0;
declare v_depth smallint unsigned default 0;
create temporary table hier(
parent_sched_id smallint unsigned,
sched_id smallint unsigned,
depth smallint unsigned default 0
)engine = memory;
insert into hier select parent_sched_id, sched_id, v_depth from schedule where sched_id = p_sched_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 schedule p inner join hier on p.parent_sched_id = hier.sched_id and hier.depth = v_depth) then
insert into hier
select p.parent_sched_id, p.sched_id, v_depth + 1 from schedule p
inner join tmp on p.parent_sched_id = tmp.sched_id and tmp.depth = v_depth;
set v_depth = v_depth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = v_depth;
else
set v_done = 1;
end if;
end while;
select
s.sched_id,
s.name as schedule_name,
p.sched_id as parent_sched_id,
p.name as parent_schedule_name,
t.trainer_id,
t.name as trainer_name,
hier.depth
from
hier
inner join schedule s on hier.sched_id = s.sched_id
inner join schedule p on hier.parent_sched_id = p.sched_id
inner join trainer t on s.trainer_id = t.trainer_id
order by
hier.depth, hier.sched_id;
drop temporary table if exists hier;
drop temporary table if exists tmp;
end #
delimiter ;
-- TEST DATA
insert into trainer (name) values ('trainer 1'),('trainer 2'),('trainer 3');
insert into schedule (name, trainer_id, parent_sched_id) values
('Schedules',null, null),
('Schedule 1',3,1),
('Schedule 2',2,1),
('Schedule 2-1',1,3),
('Schedule 2-2',3,3),
('Schedule 2-2-1',3,5),
('Schedule 2-2-2',2,5),
('Schedule 2-2-2-1',1,7);
-- TESTING
-- just call this stored procedure from your php
call schedule_hier(3);
sched_id schedule_name parent_sched_id parent_schedule_name trainer_id trainer_name depth
======== ============= =============== ==================== ========== ============ =====
3 Schedule 2 1 Schedules 2 trainer 2 0
4 Schedule 2-1 3 Schedule 2 1 trainer 1 1
5 Schedule 2-2 3 Schedule 2 3 trainer 3 1
6 Schedule 2-2-1 5 Schedule 2-2 3 trainer 3 2
7 Schedule 2-2-2 5 Schedule 2-2 2 trainer 2 2
8 Schedule 2-2-2-1 7 Schedule 2-2-2 1 trainer 1 3