2010-11-22 24 views
1

我有一些代码,我一直在使用SQL Server从另一个表中生成一个闭包表,只有直接的父/子关系,我可以运行非常简单的查询来确定沿袭。现在我需要做的这一切在MySQL,但是我有递归查询产生的闭包表的麻烦......mySQL传递闭包表

我原来的SQL服务器查询

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 

我的第一个问题是找到@@ ROWCOUNT的一个子集......但是在mySQL中递归查询可能完全不同?我也检查出Bill Karwin's presentation

PS。由于性能问题,“COLLATE DATABASE_DEFAULT”是我需要的东西。

谢谢。

回答

0

不知道如果我理解您的具体问题是什么 - 我认为这是围绕递归从邻接表表生成一棵树 - 如果是这样,下面可以帮助,但它不是递归(真可惜!)

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

更新: 感谢。我明天再看一遍。现在累了......另外,我刚刚在http://mondrian.pentaho.com/documentation/schema.php#Closure_tables上找到了代码,这很有前途,但我在重复循环中遇到了问题。 – DougF 2010-11-22 07:11:51

2

我知道这是旧的,但我觉得你还需要为别人寻找这个答案,这里是我如何生成我的闭包表从我的标准邻接表:

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

在迟到的传统中......谢谢。我会给这个破解。我实际上最终解决了它,只是没有机会一起得到答案。我会在接下来的几天检查你的答案,所以我可以关闭这个问题 - 尽管在DB中这样做,而不是PHP。谢谢。 – DougF 2012-12-18 03:56:13