MySQL查询中的递归循环可能吗?

时间:2010-11-11 21:59:05

标签: mysql nested

我正在为自己写一个论坛,我希望在顶部有一个“你在这里”字符串(“主页>论坛>子论坛>主题>等等)”。现在,论坛可以进入的深度仅限于数据库中TINYINT的128,而不是重要。

我的问题是:有没有办法选择当前论坛(使用它的ID - 简单),还要选择其中的所有内容,这样我就可以生成“你在这里”的字符串?显然,“Home>”是硬编码的,但其余的将是论坛和子论坛的标题。

我需要某种循环,从我目前所处的最深层次论坛开始,然后向上移动。使用PHP循环和大量查询是唯一的方法吗?我宁愿只使用一个,因为它更快。

谢谢,

詹姆斯

4 个答案:

答案 0 :(得分:4)

你可以通过一个简单的简单查询来做到这一点,没有连接...如果你改变你的模式,使信息易于提取。查看nested set model

答案 1 :(得分:1)

好吧,一旦你有了初始ID,你不能快速使用PHP循环来生成一组变量,用于为SQL查询生成“where”语句吗?

答案 2 :(得分:1)

这是我之前的一个可能有用的答案:Recursively check the parents of a child in a database

这是使用存储过程从php到db的非递归单次调用...

-- TABLES

drop table if exists pages;
create table pages
(
page_id smallint unsigned not null auto_increment primary key,
title varchar(255) not null,
parent_page_id smallint unsigned null,
key (parent_page_id)
)
engine = innodb;

-- TEST DATA

insert into pages (title, parent_page_id) values
('Page 1',null), 
('Page 2',null), 
   ('Page 1-2',1), 
      ('Page 1-2-1',3), 
      ('Page 1-2-2',3), 
   ('Page 2-1',2), 
   ('Page 2-2',2);


-- STORED PROCEDURES

drop procedure if exists page_parents;

delimiter #

create procedure page_parents
(
in p_page_id smallint unsigned
)
begin

declare v_done tinyint unsigned default 0;
declare v_depth smallint unsigned default 0;

create temporary table hier(
 parent_page_id smallint unsigned, 
 page_id smallint unsigned, 
 depth smallint unsigned default 0
)engine = memory;

insert into hier select parent_page_id, page_id, v_depth from pages where page_id = p_page_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 pages pg inner join hier on pg.page_id = hier.parent_page_id and hier.depth = v_depth) then

        insert into hier 
            select pg.parent_page_id, pg.page_id, v_depth + 1 from pages pg
            inner join tmp on pg.page_id = tmp.parent_page_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 
 pg.page_id,
 pg.title as page_title,
 b.page_id as parent_page_id,
 b.title as parent_page_title,
 hier.depth
from 
 hier
inner join pages pg on hier.page_id = pg.page_id
left outer join pages b on hier.parent_page_id = b.page_id
order by
 hier.depth, hier.page_id;

drop temporary table if exists hier;
drop temporary table if exists tmp;

end #

delimiter ;

-- TESTING (call this stored procedure from php)

call page_parents(5);
call page_parents(7);

答案 3 :(得分:0)

如果您假设用户使用论坛的物理层次结构进行导航,只需使用大量左连接,如下所示:

select current.forum as current,
        parent1.forum as history1,
        parent2.forum as history2,
        parent3.forum as history3,
        parent4.forum as history4,
        parent5.forum as history5,
        parent6.forum as history6
from forum current
left join forum parent1 on parent1.id = current.parentid
left join forum parent2 on parent2.id = parent1.parentid
left join forum parent3 on parent3.id = parent2.parentid
left join forum parent4 on parent4.id = parent3.parentid
left join forum parent5 on parent5.id = parent4.parentid
left join forum parent6 on parent6.id = parent5.parentid

否则,您可能需要创建一个论坛面包屑表来存储用户访问过的位置的历史记录。使用用户访问的每个位置更新此表。