2010-11-22 16 views
1

Ich habe einige Code, den ich in SQL Server verwendet habe, um eine Verschlusstabelle aus einer anderen Tabelle zu generieren, die nur die direkten Eltern/Kind-Beziehungen hat, kann ich sehr einfache Abfragen ausführen, um Herkunft zu bestimmen. Jetzt bin ich, um alles in mySQL zu tun, aber ich habe Probleme mit den rekursiven Abfragen der Verschlusstabelle zu erzeugen ...mySQL transitive Verschlusstabelle

Meine ursprüngliche SQL Server-Abfrage ist

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 

Mein erstes Problem zu finden ist eine Substitution für @@ ROWCOUNT ... aber vielleicht sind rekursive Abfragen in mySQL völlig anders? Ich habe auch ausgecheckt Bill Karwin's presentation

PS. Die "COLLATE DATABASE_DEFAULT" war etwas, das ich aufgrund von Leistungsproblemen brauchte.

Danke.

Antwort

0

nicht sicher, ob ich verstanden, was Ihr genau das Problem ist - ich denke, es wird um rekursiv einen Baum aus einer Adjazenzliste Tabelle zu erzeugen - wenn ja, kann folgendes helfen, aber es ist nicht rekursiv (was für eine Schande !!)

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

Update: Dank. Ich schaue mir das morgen wieder an. Zu müde jetzt ... Auch ich habe gerade Code bei http://mondrian.pentaho.com/documentation/schema.php#Closure_tables gefunden, der vielversprechend ist, aber ich habe Probleme mit der Wiederholungsschleife. – DougF

2

ich weiß, das ist alt, aber ich fühle mich immer noch eine Antwort auf diese für andere brauchen suchen, hier ist, wie ich meine Schließung Tisch von meinem Standard adjacency Tabelle erzeugt:

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

In der Tradition der späten Antworten ... Danke. Ich werde das einen Riss geben. Letztendlich habe ich es gelöst, ich hatte einfach keine Chance, eine Antwort zu bekommen. Ich werde Ihre Antwort in den nächsten Tagen überprüfen, damit ich diese Frage schließen kann - obwohl ich das alles in der DB mache, nicht in PHP. Vielen Dank. – DougF

Verwandte Themen