Возможно ли рекурсивное зацикливание в запросах MySQL? - PullRequest
0 голосов
/ 12 ноября 2010

Я пишу себе форум, и я хочу, чтобы в верхней части была одна из строк «Вы здесь» (вроде «home> forum> sub forum> topic> etc»).Теперь глубина, на которую могут заходить форумы, ограничена значением TINYINT, равным 128, в базе данных, но это не имеет значения.

Мой вопрос такой: есть ли способ выбрать текущий форум (используя его идентификатор)?- легко), но также выберите все, что внутри, чтобы я мог сгенерировать строку «вы здесь»?Очевидно, что «Home>» жестко запрограммировано, но остальные будут названиями форумов и подфорумов.

Мне нужен какой-то цикл, начиная с самого глубокого форума, на котором я сейчас работаю, и продвигаясьнаверхЭто единственный способ сделать это с помощью циклов PHP и большого количества запросов?Я бы предпочел просто использовать один, поскольку он быстрее.

Спасибо,

Джеймс

Ответы [ 4 ]

4 голосов
/ 12 ноября 2010

Вы можете сделать это с помощью тривиально простого запроса, без объединений ... если вы измените свою схему, чтобы сделать эту информацию легкой для извлечения. Найдите модель вложенного набора .

1 голос
/ 12 ноября 2010

Это мой предыдущий ответ, который может быть полезен: Рекурсивная проверка родителей ребенка в базе данных

Это нерекурсивный одиночный вызов из 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);
1 голос
/ 12 ноября 2010

Ну, как только у вас есть начальный идентификатор, вы не можете просто быстро использовать цикл PHP для генерации набора переменных, которые вы используете для генерации оператора "где" для вашего запроса SQL?

0 голосов
/ 12 ноября 2010

Если вы предполагаете, что пользователь перемещался с использованием физической иерархии форумов, просто используйте много левых соединений следующим образом:

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

В противном случае вы можете захотеть создать таблицу «хлебных крошек» для хранения истории местоположений, которые посетил пользователь. Обновляйте эту таблицу с каждым местоположением, которое посещает пользователь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...