Count all child nodes of hierarchical data in a table

前端 未结 3 1286
失恋的感觉
失恋的感觉 2020-12-06 14:02

I want to count number of all child nodes under any level of tree structure maintained in a table using adjacency model (parent-child key). Table structure and data looks l

相关标签:
3条回答
  • 2020-12-06 14:34

    Below is a PHP based solution:

    function countChildren($startId) {
        $directDescendents = *_query("SELECT id FROM Table WHERE parentid = ?", array( $startId ));
        $count = *_num_rows($directDescendents);
        while($row = *_fetch_array($directDescendents))
            $count += countChildren($row['id']);
        return $count;
    }
    
    $numChildren = countChildren(2); // Number of Children for 'B'
    

    Replace *_num_rows and *_fetch_array with whatever functions for the SQL extension you are using. This won't be as efficient as a pure SQL solution, but it will work. The way I'm querying in the function is assuming bound parameters, but execute the query as you like.

    0 讨论(0)
  • 2020-12-06 14:40

    Can be done fairly simply with a non-recursive stored procedure as follows:

    Example calls

    mysql> call category_hier(1);
    +--------------+
    | num_children |
    +--------------+
    |            3 |
    +--------------+
    1 row in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> call category_hier(2);
    +--------------+
    | num_children |
    +--------------+
    |            2 |
    +--------------+
    1 row in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    

    Full script

    drop table if exists categories;
    create table categories
    (
    cat_id smallint unsigned not null auto_increment primary key,
    name varchar(255) not null,
    parent_cat_id smallint unsigned null,
    key (parent_cat_id)
    )
    engine = innodb;
    
    insert into categories (name, parent_cat_id) values
    ('Location',null), 
    ('Color',null), 
       ('USA',1), 
          ('Illinois',3), 
          ('Chicago',3), 
       ('Black',2), 
       ('Red',2);
    
    
    drop procedure if exists category_hier;
    delimiter #
    
    create procedure category_hier
    (
    in p_cat_id smallint unsigned
    )
    begin
    
    declare v_done tinyint unsigned default 0;
    declare v_depth smallint unsigned default 0;
    
    create temporary table hier(
     parent_cat_id smallint unsigned, 
     cat_id smallint unsigned, 
     depth smallint unsigned default 0
    )engine = memory;
    
    insert into hier select parent_cat_id, cat_id, v_depth from categories where cat_id = p_cat_id;
    create temporary table tmp engine=memory select * from hier;
    
    /* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
    
    while not v_done do
    
        if exists( select 1 from categories c
            inner join tmp on c.parent_cat_id = tmp.cat_id and tmp.depth = v_depth) then
    
            insert into hier select c.parent_cat_id, c.cat_id, v_depth + 1 from categories c
                inner join tmp on c.parent_cat_id = tmp.cat_id and tmp.depth = v_depth;
    
            set v_depth = v_depth + 1;          
    
            truncate table tmp;
            insert into tmp select * from hier where depth = v_depth;
    
        else
            set v_done = 1;
        end if;
    
    end while;
    
    /*
    select 
     c.cat_id,
     c.name as category_name,
     p.cat_id as parent_cat_id,
     p.name as parent_category_name,
     hier.depth
    from 
     hier
    inner join categories c on hier.cat_id = c.cat_id
    left outer join categories p on hier.parent_cat_id = p.cat_id
    order by
     hier.depth;
    */
    
    select count(*) as num_children from hier where parent_cat_id is not null;
    
    drop temporary table if exists hier;
    drop temporary table if exists tmp;
    
    end #
    
    delimiter ;
    
    call category_hier(1);
    
    call category_hier(2);
    

    You can easily adapt this example to suit your requirements.

    Hope it helps :)

    0 讨论(0)
  • 2020-12-06 14:41

    The way you store your data will not allow for a simple query to get the total child count. But have a look at:

    http://en.wikipedia.org/wiki/Nested_set_model

    Where a query like this would be possible.

    0 讨论(0)
提交回复
热议问题