【问题标题】:Is recursive looping in MySQL queries possible?MySQL查询中的递归循环是否可能?
【发布时间】:2010-11-12 06:12:57
【问题描述】:

我正在给自己写一个论坛,我想在顶部有一个“你在这里”字符串(“主页 > 论坛 > 子论坛 > 主题 > 等等”之类的东西)。现在,论坛可以访问的深度仅限于数据库中 TINYINT 的 128 之类的内容,这并不重要。

我的问题是:有没有办法选择当前论坛(使用它的 ID - 简单),但也选择它里面的所有其他内容,以便我可以生成“你在这里”字符串?显然“首页>”是硬编码的,剩下的就是论坛和子论坛的标题。

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

谢谢,

詹姆斯

【问题讨论】:

  • 您需要的是分层查询,但 MySQL 不直接支持这些。您可以通过创建存储函数来解决此问题。请参阅此处了解一些(诚然相当老的)提示:bugs.mysql.com/bug.php?id=2341

标签: mysql nested


【解决方案1】:

您可以通过非常简单的查询来完成此操作,无需连接...如果您更改架构以使该信息易于提取。查找nested set model

【讨论】:

【解决方案2】:

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

【讨论】:

  • 我决定使用 PHP 循环来为我完成繁重的工作。感谢使用 MySQL 而不是 PHP 进行处理的概念 - 一个查询意味着快速查询 :) 欢迎来到 Stack Overflow bikeboy!
【解决方案3】:

这是我以前的答案,可能有用: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);

【讨论】:

  • 当我有更多时间时,我一定会研究这个 - 谢谢。
【解决方案4】:

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

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

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

【讨论】:

  • 面包屑表可以,但我认为 PHP 循环是这里的最佳选择。不过还是谢谢你:-)
  • 这太过分了,where 在哪里?你想把所有东西都扔掉
猜你喜欢
  • 2017-04-24
  • 2016-09-28
  • 1970-01-01
  • 2014-10-01
  • 2023-03-29
  • 2021-12-17
  • 2012-07-21
  • 2012-06-22
  • 2020-07-29
相关资源
最近更新 更多