2010-11-22 23 views
1

J'ai du code que j'ai utilisé dans SQL Server pour générer une table de fermeture à partir d'une autre table qui n'a que les relations parent/enfant directes, je peux lancer des requêtes très simples pour déterminer le lignage. Maintenant, je besoin de faire tout cela dans mySQL, mais je ne parviens pas à avec l'interrogation récursive pour générer la table de fermeture ...Table de fermeture transitive mySQL

Ma requête d'origine du serveur SQL est

WHILE @@ROWCOUNT>0 
INSERT INTO [ClosureTable] ([Ancestor], [Descendent]) 
SELECT distinct [Parent],[tc].[Descendent] 
FROM 
    [RelationshipTable] 
INNER JOIN [ClosureTable] as tc 
    ON [Child]COLLATE DATABASE_DEFAULT = 
         [tc].[Ancestor]COLLATE DATABASE_DEFAULT 
LEFT OUTER JOIN [ClosureTable] As tc2 
    ON [Parent]COLLATE DATABASE_DEFAULT = 
         [tc2].[Ancestor] COLLATE DATABASE_DEFAULT 
    AND [tc].[Descendent]COLLATE DATABASE_DEFAULT = 
         [tc2].[Descendent]COLLATE DATABASE_DEFAULT 

Mon premier problème est de trouver une substitution pour @@ ROWCOUNT ... mais peut-être que les requêtes récursives sont complètement différentes dans mySQL? J'ai également vérifié Bill Karwin's presentation

PS. Le "COLLATE DATABASE_DEFAULT" était quelque chose dont j'avais besoin en raison de problèmes de performance ..

Merci.

Répondre

0

ne sais pas si je compris ce que votre problème exact est - je pense qu'il est autour de la génération récursive un arbre à partir d'une table de liste de contiguïté - le cas échéant, peuvent aider, mais ce n'est pas récursif (quelle honte !!)

drop table if exists employees; 
create table employees 
(
emp_id smallint unsigned not null auto_increment primary key, 
name varchar(255) not null, 
boss_id smallint unsigned null, 
key (boss_id) 
) 
engine = innodb; 

insert into employees (name, boss_id) values 
('f00',null), 
    ('ali later',1), 
    ('megan fox',1), 
    ('jessica alba',3), 
    ('eva longoria',3), 
    ('keira knightley',5), 
     ('liv tyler',6), 
     ('sophie marceau',6); 


drop procedure if exists employees_hier; 

delimiter # 

create procedure employees_hier 
(
in p_emp_id smallint unsigned 
) 
begin 

declare v_done tinyint unsigned default(0); 
declare v_dpth smallint unsigned default(0); 

create temporary table hier(
boss_id smallint unsigned, 
emp_id smallint unsigned, 
depth smallint unsigned 
)engine = memory; 

insert into hier select boss_id, emp_id, v_dpth from employees where emp_id = p_emp_id; 

/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */ 

create temporary table emps engine=memory select * from hier; 

while not v_done do 

if exists(select 1 from employees e inner join hier on e.boss_id = hier.emp_id and hier.depth = v_dpth) then 

    insert into hier select e.boss_id, e.emp_id, v_dpth + 1 
    from employees e inner join emps on e.boss_id = emps.emp_id and emps.depth = v_dpth; 

    set v_dpth = v_dpth + 1; 

    truncate table emps; 
    insert into emps select * from hier where depth = v_dpth; 

else 
    set v_done = 1; 
end if; 

end while; 

select 
e.emp_id, 
e.name as emp_name, 
p.emp_id as boss_emp_id, 
p.name as boss_name, 
hier.depth 
from 
hier 
inner join employees e on hier.emp_id = e.emp_id 
left outer join employees p on hier.boss_id = p.emp_id; 

drop temporary table if exists hier; 
drop temporary table if exists emps; 

end # 

delimiter ; 

-- call this sproc from your php 

call employees_hier(1); 
+0

mise à jour: Merci. Je vais regarder ça encore demain. Pour fatiguer maintenant ... Aussi, je viens de trouver du code sur http://mondrian.pentaho.com/documentation/schema.php#Closure_tables qui est prometteur mais, j'ai des problèmes avec la boucle de répétition. – DougF

2

je sais que c'est vieux, mais je pense que vous avez encore besoin d'une réponse à ce sujet pour les autres à la recherche, voici comment je généré ma table de fermeture de ma table standard contiguïté:

mysql_query('TRUNCATE fec_categories_relations'); 

function rebuild_tree($parent) 
{ 
    // get all children of this node 
    $result = mysql_query('SELECT c.categories_id, c.parent_id, cd.categories_name FROM fec_categories c 
          INNER JOIN fec_categories_description cd ON c.categories_id = cd.categories_id 
          WHERE c.parent_id = "'.$parent.'" 
          AND  cd.language_id = 1 
          ORDER BY cd.categories_name'); 

    // loop through 
    while ($row = mysql_fetch_array($result)) 
    {  
     $update_sql = " INSERT fec_categories_relations (ancestor, descendant, length) 
         SELECT ancestor, {$row['categories_id']}, length+1 
         FROM fec_categories_relations 
         WHERE descendant = {$row['parent_id']} 
         UNION ALL SELECT {$row['categories_id']},{$row['categories_id']}, 0"; 

     mysql_query($update_sql); 

     echo '<li>' . $update_sql . "</li>"; 

     rebuild_tree($row['categories_id']); 
    } 
} 

rebuild_tree(0); 
+0

Dans la tradition des derniers respones ... Merci. Je vais donner une fissure. En fait, j'ai fini par le résoudre, mais je n'ai pas eu la chance d'avoir une réponse ensemble. Je vais vérifier votre réponse au cours des deux prochains jours, donc je peux fermer cette question - bien que faisant tout cela dans la DB, pas php. Merci. – DougF