MySQL recursive tree search

前端 未结 6 958
臣服心动
臣服心动 2020-12-17 07:06

I have a database with a tree of names that can go down a total of 9 levels deep and I need to be able to search down a signal branch of the tree from any point on the branc

6条回答
  •  别那么骄傲
    2020-12-17 07:16

    You can do this with a stored procedure as follows:

    Example calls

    mysql> call names_hier(1, 'a');
    +----+----------+--------+-------------+-------+
    | id | emp_name | parent | parent_name | depth |
    +----+----------+--------+-------------+-------+
    |  2 | ali      |      1 | f00         |     1 |
    |  8 | anna     |      6 | keira       |     4 |
    +----+----------+--------+-------------+-------+
    2 rows in set (0.00 sec)
    
    mysql> call names_hier(3, 'k');
    +----+----------+--------+-------------+-------+
    | id | emp_name | parent | parent_name | depth |
    +----+----------+--------+-------------+-------+
    |  6 | keira    |      5 | eva         |     2 |
    +----+----------+--------+-------------+-------+
    1 row in set (0.00 sec)
    
    $sqlCmd = sprintf("call names_hier(%d,'%s')", $id, $name);  // dont forget to escape $name
    $result = $db->query($sqlCmd);
    

    Full script

    drop table if exists names;
    create table names
    (
    id smallint unsigned not null auto_increment primary key,
    name varchar(255) not null,
    parent smallint unsigned null,
    key (parent)
    )
    engine = innodb;
    
    insert into names (name, parent) values
    ('f00',null), 
      ('ali',1), 
      ('megan',1), 
          ('jessica',3), 
          ('eva',3), 
             ('keira',5), 
                ('mandy',6), 
                ('anna',6);
    
    drop procedure if exists names_hier;
    
    delimiter #
    
    create procedure names_hier
    (
    in p_id smallint unsigned,
    in p_name varchar(255)
    )
    begin
    
    declare v_done tinyint unsigned default(0);
    declare v_dpth smallint unsigned default(0);
    
    set p_name = trim(replace(p_name,'%',''));
    
    create temporary table hier(
     parent smallint unsigned, 
     id smallint unsigned, 
     depth smallint unsigned
    )engine = memory;
    
    insert into hier select parent, id, v_dpth from names where id = p_id;
    
    /* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
    
    create temporary table tmp engine=memory select * from hier;
    
    while not v_done do
    
        if exists( select 1 from names n inner join tmp on n.parent = tmp.id and tmp.depth = v_dpth) then
    
            insert into hier select n.parent, n.id, v_dpth + 1 
                from names n inner join tmp on n.parent = tmp.id and tmp.depth = v_dpth;
    
            set v_dpth = v_dpth + 1;            
    
            truncate table tmp;
            insert into tmp select * from hier where depth = v_dpth;
    
        else
            set v_done = 1;
        end if;
    
    end while;
    
    
    select 
     n.id,
     n.name as emp_name,
     p.id as parent,
     p.name as parent_name,
     hier.depth
    from 
     hier
    inner join names n on hier.id = n.id
    left outer join names p on hier.parent = p.id
    where
     n.name like concat(p_name, '%');
    
    drop temporary table if exists hier;
    drop temporary table if exists tmp;
    
    end #
    
    delimiter ;
    
    -- call this sproc from your php
    
    call names_hier(1, 'a');
    call names_hier(3, 'k');
    

提交回复
热议问题