mySQL 传递闭包表

发布于 2024-10-04 04:53:20 字数 951 浏览 4 评论 0原文

我在 SQL Server 中使用了一些代码,从另一个仅具有直接父/子关系的表生成闭包表,我可以对此运行非常简单的查询来确定沿袭。现在我需要在 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 的演示

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

谢谢。

I have some code I've been using in SQL Server to generate a closure table from another table that has just the direct parent/child relationships, I can run very simple queries against this to determine lineage. Now I am needing to do all this in mySQL, but I am having trouble with the recursive querying to generate the closure table...

My original SQL server query is

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

My first problem is finding a substiture for @@ROWCOUNT... but perhaps recursive queries are completely different in mySQL? I've also checked out Bill Karwin's presentation

PS. The "COLLATE DATABASE_DEFAULT" was something I needed due to performance issues..

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如梦亦如幻 2024-10-11 04:53:20

我知道这已经很旧了,但我觉得您仍然需要为其他人提供答案,以下是我从标准邻接表生成闭包表的方法:

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

I know this is old, but I feel you still need an answer on this for others looking, here is how I generated my closure table from my standard adjacency table:

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);
多情癖 2024-10-11 04:53:20

不确定我是否理解你的确切问题是什么 - 我认为这是从邻接列表表递归生成一棵树 - 如果是这样,以下内容可能会有所帮助,但它不是递归的(真可惜!)

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

not sure if i understood what your exact problem is - i think it's around recursively generating a tree from an adjacency list table - if so, the following may help but it's not recursive (what a shame !!)

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文