计算sql中的分层子节点的数量

时间:2015-05-29 15:01:02

标签: mysql sql join common-table-expression recursive-cte

我有一个存储父母和左子女和右子信息的表。如何计算孩子的数量属于那个父母?

例如我的表结构是:

parent  left  right
--------------------
 1        2     3
 3        4     5
 4        8     9
 5        10    11
 2        6     7
 9        12    null

如何计算任何父节点的子节点数。
例如,4包含以下分层子节点 - 8,9,12,因此子节点数为3 3包含以下子节点 - > 4,5,10,11,8,9,12所以孩子总数为7。

如何使用SQL查询实现此目的?

1 个答案:

答案 0 :(得分:0)

create table mytable
(   parent int not null,
    cleft int null,
    cright int null
)
insert into mytable (parent,cleft,cright) values (1,2,3);
insert into mytable (parent,cleft,cright) values (2,6,7);
insert into mytable (parent,cleft,cright) values (3,4,5);
insert into mytable (parent,cleft,cright) values (4,8,9);
insert into mytable (parent,cleft,cright) values (5,10,11);
insert into mytable (parent,cleft,cright) values (6,null,null);
insert into mytable (parent,cleft,cright) values (7,null,null);
insert into mytable (parent,cleft,cright) values (8,13,null);
insert into mytable (parent,cleft,cright) values (9,12,null);
insert into mytable (parent,cleft,cright) values (10,null,null);
insert into mytable (parent,cleft,cright) values (12,null,null);
insert into mytable (parent,cleft,cright) values (13,null,17);
insert into mytable (parent,cleft,cright) values (17,null,null);


DELIMITER $$
CREATE procedure GetChildCount (IN parentID INT)
DETERMINISTIC
BEGIN
    declare ch int;
    declare this_left int;
    declare this_right int;
    declare bContinue boolean;
    declare count_needs_scan int;

    create temporary table asdf999 (node_id int,processed int);
    -- insert into asdf999 (node_id,processed) values (1,0);
    -- update asdf999 set processed=1;

    SET ch = parentID;
    set bContinue=true;
    while bContinue DO
        -- at this point you are sitting at a ch (anywhere in hierarchy)
        -- as you are looping and getting/using children

        -- save non-null children references: -----------------------------
        select cleft into this_left from mytable where parent=ch;
        if !isnull(this_left) then
            insert asdf999 (node_id,processed) select this_left,0;
        end if;

        select cright into this_right from mytable where parent=ch;
        if !isnull(this_right) then
            insert asdf999 (node_id,processed) select this_right,0;
        end if;
        -- -----------------------------------------------------------------
        select count(*) into count_needs_scan from asdf999 where processed=0;
        if count_needs_scan=0 then
            set bContinue=false;
        else
            select node_id into ch from asdf999 where processed=0 limit 1;
            update asdf999 set processed=1 where node_id=ch;
            -- well, it is about to be processed
        end if;
    END WHILE;
    select count(*) as the_count from asdf999;
    drop table asdf999;
END $$
DELIMITER ;
call GetChildCount(2);  -- answer is 2
call GetChildCount(4);  -- answer is 5

我可以提供一个版本,创建一个动态命名的表(或临时表),如果你愿意,可以在最后使用它。程序内部的“动态sql / prepare statment”。通过共享使用工作表asdf999,用户将不会相互衔接。所以这不是生产准备。但上面给出了概念的概念