动态查询一个树形结构表中:某一个节点的所有父节点或者子节点

mysql:动态查询一个树形结构表中:某一个节点的所有父节点或者子节点

根据传过来的表名和关系字段名可以动态找到某个某一个节点的所有父节点或者子节点

  • schema_name
  • table_name
  • type :1、父级2、子级
  • self_value: 节点值
  • id_name:节点主键id,用于查找子节点
  • self_name:本节点的字段名称,用于找父级
  • parent_name:父节点名称,用于找子级和父级
  • rt_value:返回值,MEDIUMTEXT,最大16777215(2^24-1)

辅助方法

CREATE FUNCTION `func_get_split_string`(`f_string` varchar(1000), `f_delimiter` varchar(5), `f_order` int)
    RETURNS varchar(255) CHARSET utf8
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN
#592876
#f_string字符串按f_delimiter截取后获取第f_order位
  declare result varchar(255) default '';
  declare oneSub varchar(255) default '';
  declare cou int default 0;

  set cou=1+(length(f_string) - length(replace(f_string,f_delimiter,''))); 


  if f_order>cou then 
    return result;
  end if;
  set result = reverse(substring_index(reverse(substring_index(f_string,f_delimiter,f_order)),f_delimiter,1));
  return result;
END

子存储过程

CREATE PROCEDURE `pro_find_tree_recursion`(IN `table_name` VARCHAR(50), IN `parent_name` VARCHAR(50), IN `id_name` VARCHAR(50), IN `self_value` VARCHAR(50), INOUT `rt_value` MEDIUMTEXT)
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
recur:BEGIN
    DECLARE done INT DEFAULT 0;
   DECLARE b VARCHAR (32);
    DECLARE all_value VARCHAR (1000);
    DECLARE tree_sql1 VARCHAR (1000);
    DECLARE cou INT default 0;
    DECLARE ALL_VALUE_COU INT default 0;
    DECLARE one_value VARCHAR (100);
    DECLARE max_loop INT DEFAULT 0;
    DECLARE now_loop INT DEFAULT 0;




    set @@session.max_sp_recursion_depth=20;

    #现将自己塞进来
    if length(rt_value)=0 or rt_value is null
        then 
            set rt_value=concat(self_value);
        else 
            set rt_value=concat(rt_value,';',self_value);
    end if;


    #查找出自己所有的下级
    set tree_sql1= concat('select   GROUP_CONCAT(',id_name,') into @l_value ',/*,id_name,' into @l_id','*/'from ',table_name,' t where t.',parent_name,' = ',self_value);
    #select tree_sql1;
    set @tree_sql1=tree_sql1;  
     prepare stmt from @tree_sql1; 
     EXECUTE stmt;     
     deallocate prepare stmt;    
     set all_value=@l_value;

    #如果没有下级,返回上一层
    if length(all_value)=0 or all_value is null
    then 
        leave recur;
    end if;



    #如果有下级,则继续循环
    rec_while :while 1=1
        do
            set now_loop=now_loop+1;
            set one_value=func_get_split_string(all_value,',',now_loop);
            if length(one_value)=0 or one_value is null then
            #下级循环结束,返回上一层
                leave rec_while;
            end if;
            #继续找下级的子节点
            call pro_find_tree_recursion(table_name,parent_name,id_name,one_value,rt_value);
    end while;

    leave recur;
END

主存储过程

CREATE PROCEDURE `pro_find_tree_value`(IN `schema_name` VARCHAR(50), IN `table_name` VARCHAR(50), IN `type` INT, IN `self_value` VARCHAR(50), IN `id_name` VARCHAR(50), IN `self_name` VARCHAR(50), IN `parent_name` VARCHAR(50), IN `recure_num` INT, INOUT `rt_value` MEDIUMTEXT)
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
pro_begin:BEGIN  

DECLARE _value varchar(100);
DECLARE rtValue text default '';
DECLARE _schema varchar(100);
DECLARE cou int;
DECLARE tree_sql1 VARCHAR(500);
DECLARE id_value varchar(100);


if length(schema_name)=0
    then select database() into _schema;
else  set _schema=schema_name ;
end if;



 select count(1) into cou
       from information_schema.columns a  where a.table_schema = _schema and a.table_name= table_name 
       and a.column_name=self_name;
if cou=0

    then  leave pro_begin;
end if;

 select count(1) into cou
       from information_schema.columns a  where a.table_schema = _schema and a.table_name= table_name 
       and a.column_name=parent_name;
if cou=0
    then  leave pro_begin;
end if;

    set tree_sql1= concat('select count(1) into @l_value from ',table_name,' t where t.',self_name,' = ',self_value);
        select tree_sql1;
    set @tree_sql1=tree_sql1;   ##注意很重要,将连成成的字符串赋值给一个变量(可以之前没有定义,但要以@开头)
     prepare stmt from @tree_sql1;  ##预处理需要执行的动态SQL,其中stmt是一个变量
     EXECUTE stmt;      ##执行SQL语句
     deallocate prepare stmt;     ##释放掉预处理段
     set cou=@l_value;
     select cou;
     if cou=0
        then leave pro_begin;
    end if;

    #type =1
    #table_name的self_name值为self_value,返回parent_name的上级的上级的上级....(用分号隔开)
    if type =1 then 
        ontTypeLoop:loop
            set tree_sql1= concat('select ',parent_name,' into @l_value ',/*,id_name,' into @l_id','*/'from ',table_name,' t where t.',self_name,' = ',self_value);
            #select tree_sql1;
        set @tree_sql1=tree_sql1;   ##注意很重要,将连成成的字符串赋值给一个变量(可以之前没有定义,但要以@开头)
         prepare stmt from @tree_sql1;  ##预处理需要执行的动态SQL,其中stmt是一个变量
         EXECUTE stmt;      ##执行SQL语句
         deallocate prepare stmt;     ##释放掉预处理段

     if length(rt_value)=0 or rt_value is null
        then 
            set rt_value=concat(@l_value);
        else 
            set rt_value=concat(rt_value,';',@l_value);
        end if;


        set self_value=@l_value;

        set tree_sql1= concat('select count(1) into @l_value from ',table_name,' t where t.',self_name,' = ',self_value);
    set @tree_sql1=tree_sql1;  
     prepare stmt from @tree_sql1;  
     EXECUTE stmt;      
     deallocate prepare stmt;    
     set cou=@l_value;
        if cou=0
            then leave ontTypeLoop;
        end if;
    end loop;

   end if;

   #type =2
   #树的子节点查询:根节点值:self_value,上级节点名:parent_name,节点id名:id_name
    #利用递归返回table_name的parent_name值为self_value的下级的下级的下级....
   if type=2 then
    select 1;
        call pro_find_tree_recursion(table_name,parent_name,id_name,self_value,rt_value);

    end if; 

   leave pro_begin;
END

你可能感兴趣的:(mysql)