2010-11-11 105 views
0

我正在为自己写一个论坛,并且我希望在顶部有一个“你在这里”字符串(“主页>论坛>子论坛>主题>等等”)。现在,论坛可以使用的深度仅限于TINYINT在数据库中的128位,这并不重要。是否可以在MySQL查询中进行递归循环?

我的问题是这样的:有没有办法选择当前的论坛(使用它的ID - 容易),但也选择其内部的一切,所以我可以生成“你在这里”字符串?显然,“家庭”是硬编码的,但其余的将是论坛和分论坛的标题。

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

感谢,

詹姆斯

+0

你需要的是一分层查询,但MySQL不直接支持这些。你可以通过创建一个存储函数来解决这个问题。看到这里的一些(不可否​​认的是比较老的)技巧:http://bugs.mysql.com/bug.php?id=2341 – 2010-11-11 22:13:22

回答

1

那么,一旦你有了初始ID,你能不能快速地使用PHP循环来生成一组变量,你用它来为你的SQL查询生成一个“where”语句?

+0

我已经决定在一个PHP循环为我做繁重的工作。感谢处理使用MySQL而不是PHP的概念 - 一个查询意味着快速查询:)欢迎来到Stack Overflow bikeboy! – Bojangles 2010-11-11 22:10:15

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 

否则,你可能想要创建一个论坛breadcrumb表来存储用户访问过的位置的历史记录。用用户访问的每个位置更新此表。

+0

面包屑表会好的,但我认为PHP循环是最好的选择。感谢所有相同,但:-) – Bojangles 2010-11-11 22:08:22

+0

这是过度的,哪里是'哪里'?你试图抛弃所有的东西 – ajreal 2010-11-11 22:15:12

4

你可以用一个简单的查询来做到这一点,没有联合......如果你改变你的模式,使得信息易于提取。查找nested set model

+0

非常感谢。我会明天看看,因为它迟到了.-) – Bojangles 2010-11-11 22:14:30

+1

嵌套集是我用来创建我的网站导航。非常强大的东西。这里有一篇关于在MySQL中使用它的好文章:http://dev.mysql.com/tech-resources/articles/hierarchical-data.html – Sonny 2010-11-11 22:29:11

+0

谢谢你好先生:-) – Bojangles 2010-11-12 08:07:03

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); 
+0

当我有更多时间时,我一定会考虑这一点 - 谢谢。 – Bojangles 2010-11-15 08:45:50