2010-11-11 14 views
0

Je m'écris moi-même un forum, et je veux avoir une de ces chaînes "vous êtes ici" en haut de la page ("home> forum> sous-forum> topic> etc"). Maintenant, la profondeur que les forums peuvent atteindre est limitée à quelque chose comme 128 par TINYINT dans la base de données, pas que cela soit important.Une boucle récursive dans les requêtes MySQL est-elle possible?

Ma question est la suivante: existe-t-il un moyen de sélectionner le forum actuel (en utilisant son identifiant - facile), mais aussi de sélectionner tout ce qu'il contient pour générer la chaîne "you are here"? Évidemment "Home>" est codé en dur, mais le reste sera des titres de forums et sous-forums.

J'ai besoin d'une sorte de boucle, en commençant par le forum de niveau le plus profond dans lequel je suis actuellement et en montant au sommet. Est-ce la seule façon de le faire en utilisant des boucles PHP et beaucoup de requêtes? Je préfère en utiliser un car c'est plus rapide.

Merci,

James

+0

Qu'est-ce que vous avez besoin est un requête hiérarchique, mais MySQL ne les supporte pas directement. Vous pouvez contourner ce problème en créant une fonction stockée. Voyez ici quelques conseils (certes un peu vieux): http://bugs.mysql.com/bug.php?id=2341 –

Répondre

1

Eh bien, une fois que vous avez l'ID initial, ne pouvez-vous pas utiliser rapidement une boucle PHP pour générer un ensemble de variables que vous utilisez pour générer une instruction "where" pour votre requête SQL?

+0

J'ai décidé de faire une boucle PHP pour faire le gros du travail. Merci pour la notion de traitement en utilisant MySQL pas PHP - une requête signifie une requête rapide :) Welcom à Stack Overflow bikeboy! – Bojangles

0

Si vous assumez l'utilisateur navigue en utilisant la hiérarchie physique des forums, il suffit d'utiliser beaucoup de gauche rejoint comme suit:

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 

Sinon, vous pouvez vouloir créer une table de fil d'Ariane pour stocker l'historique des lieux que l'utilisateur a visités. Mettez à jour cette table avec chaque emplacement visité par l'utilisateur.

+0

Une table de navigation serait ok, mais je pense qu'une boucle PHP est la meilleure option ici. Merci tout de même :-) – Bojangles

+0

c'est trop, et où est le 'where'? J'essaie de tout vider – ajreal

4

Vous pouvez le faire avec une requête trivialement simple, sans jointures ... si vous modifiez votre schéma pour rendre cette information facile à extraire. Rechercher le nested set model.

+0

Merci beaucoup. Je vais regarder dans ce demain car il se fait tard :-) – Bojangles

+1

Ensembles imbriqués est ce que j'utilise pour créer ma navigation sur le site Web. Des trucs très puissants. Il y a un bon article sur le faire en MySQL ici: http://dev.mysql.com/tech-resources/articles/hierarchical-data.html – Sonny

+0

Merci yee bon monsieur :-) – Bojangles

1

Ceci est une réponse précédente de la mine qui pourrait être utile: Recursively check the parents of a child in a database

Il est un seul appel non récurrent de php db en utilisant une procédure stockée ...

-- 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

Je vais certainement regarder dans ce quand j'ai plus de temps - merci. – Bojangles