• mysql建立的一个自动更新组织树案案例


    组织树实现案例

    一、实现功能:
    根据组织基表organizitions,更新组织树子树表orgs,子树表包括每个组织树的节点为顶点子树,以及带层级格式子树。新增,删除,修改组织树基表organizitions,同时修改组织树子树表orgs。删除organizitions时,如果该节点具有子树节点,需要完成所有的子树删除后,才能删除该节点。

    组织树举例:

    子树排序顺序:1,2,4,6,3,5,7 (穷尽每一条线在开始第二条线)

    假设以上各节点为organization表的ID为例,则org表中数据为:
    id 父树 Id为顶点树 id为顶点的带层级格式子树
    (层级说明:顶点下一层为一级,以此类推)
    1 1,2,4,6,3,5,7 1,-2,--4,--6,-3,--5,-7
    2 1 2,4,6 2,-4,-6
    3 1 3,5 3,-5
    5 1,3
    7 1

    二、建表:
    1、组织树表(organizitions)
    序号 字段名 类型 备注
    1 Id int 主键自增字段
    2 Name Varchar(64)
    3 Seq int 同层级排列顺序
    4 adress Varchar(200)
    5 Organization_id int

    2、各节点子树父树序号表(orgs)
    序号 字段名 类型 备注
    1 Organization_id int 主键非自增
    2 Parent_ids Varchar(100) 父树
    3 Child_ids Varchar(100) 子树
    4 Child_ids_format Varchar(100) 子树节点带-

    建表脚本:
    DROP TABLE IF EXISTS organizitions;
    CREATE TABLE organizitions (
    id int(11) NOT NULL AUTO_INCREMENT,
    name varchar(64) DEFAULT NULL,
    seq int(11) DEFAULT NULL,
    address varchar(200) DEFAULT NULL,
    organizition_id int(11) DEFAULT NULL,
    PRIMARY KEY (id),
    KEY organizition_id (organizition_id)
    ) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;

    DROP TABLE IF EXISTS orgs;
    CREATE TABLE orgs (
    organizition_id int(11) NOT NULL DEFAULT '0',
    parent_ids varchar(100) DEFAULT NULL,
    child_ids varchar(100) DEFAULT NULL,
    child_ids_format varchar(100) DEFAULT NULL,
    PRIMARY KEY (organizition_id),
    KEY organizition_id (organizition_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    三、实现子树对应ORGS表中存储举例:
    以下organizations表数据为例,假设组织树节点为:
    以如下organizations数据为例:(同层级树排序按照seq顺序排列)

    (1)顶点1为案例的树

    顶点1不带层级树:

    顶点1带层级树:

    在orgs表中,对应为organizition_id为1的一行数据,字段child_ids,child_ids_format为带层级格式和不带层级格式数据。
    如下图:

    (2)顶点3为案例的树
    顶点3不带层级树:

    顶点3带层级子树:

    对应ORGS表内容:

    四、实现脚本


    -- 获取指定ID为顶点的子树


    drop function if exists getchild;
    create function getchild(sid varchar(500))
    returns varchar(500)
    begin
    declare org_id int;
    declare lentree int ;
    declare lentemptree int ;
    declare lenlasttree int;
    declare orgtree varchar(500);
    declare cursortree varchar(500);
    declare cid varchar(10);
    declare ctree varchar(500);
    declare foretree varchar(500);
    declare lasttree varchar(500);
    declare temp_tree varchar(500);
    declare lenid int;

    select id into org_id from organizitions where organizition_id is null;

    set org_id=cast(sid as SIGNED int);
    set foretree='';
    select GROUP_CONCAT(id order by seq) into ctree from organizitions where organizition_id=org_id ;
    set lasttree=ctree;

    insert into test2(id,foretree,lasttree) values(org_id,foretree,lasttree);

    select length(ctree) into lentree ;
    if lentree >0 THEN
    set cid=get_leftid(ctree);
    set foretree=org_id;
    select length(cid) into lenid;
    set lasttree=get_lasttree(ctree,lenid);
    set org_id=cast(cid as SIGNED int);
    while org_id > 0 DO
    select GROUP_CONCAT(id order by seq) into temp_tree from organizitions where organizition_id=org_id order by seq;
    select length(temp_tree) into lentree;
    if lentree>0 THEN
    select length(lasttree) into lenlasttree;
    if lenlasttree > 0 then
    set lasttree=concat(temp_tree,',',lasttree);
    else
    set lasttree=temp_tree;
    end if;
    select length(temp_tree) into lentemptree;
    END IF;
    set temp_tree=lasttree;
    #insert into test2(id,foretree,lasttree) values(org_id,foretree,lasttree);
    set cid=get_leftid(temp_tree);
    select length(cid) into lenid;
    if lenid >0 THEN
    set foretree=concat(foretree,',',org_id);
    set lasttree=get_lasttree(temp_tree,lenid);
    ELSE
    set cid='0';
    set orgtree=concat(foretree,',',org_id);
    end if;
    set org_id=cast(cid as SIGNED int);
    end while;
    else
    set foretree=org_id;
    end if;
    return orgtree;
    end;


    -- 字符处理函数,返回字符串最后一个逗号后的字符串 '-1,---2,-3,-4,---5'返回到---5


    drop function if exists get_formatid;
    create function get_formatid(sid varchar(20),stree varchar(100))
    returns varchar(20)
    -- returns int
    begin
    -- 将sid变为前后带-的字符,2变为'-2-',stree中逗号替换为'-',之后进行定位,获取正确formatid为带逗号最后一个字符串。
    -- 例如'---2,---1,---5' 中,寻找'1'的带'-'格式字符串'---',处理后获得字符串'---2,---1',在取最后一个逗号后的字符串,获取正确结果
    declare format_id varchar(20);
    declare ctree varchar(500);
    declare left_tree varchar(500);
    declare loc int;
    declare lenid int;
    set sid=concat('-',sid,'-');
    set ctree=concat(replace(stree,',','-'),'-');
    set loc=locate(sid,ctree);
    select length(sid) into lenid;
    set left_tree=concat(',',left(stree,loc+lenid-2));
    select REVERSE(left(REVERSE(left_tree),LOCATE(',',REVERSE(left_tree))-1)) into format_id;
    return format_id;
    end;


    -- get_leftid,取第一个逗号左边的整数。如果字符串为空,则返回空,如果没有逗号,
    -- select left('1,2,3',LOCATE(',','1,2,3')-1)


    drop function if exists get_leftid;
    create function get_leftid(stree varchar(500))
    -- 设置函数的返回类型
    returns varchar(500)
    begin-- 函数头
    declare len int;
    set len=length(stree);
    if len=0 then
    set stree='';
    ELSE
    if locate(',',stree)>0 THEN
    set stree=left(stree,locate(',',stree)-1);
    end if;
    end if;
    return stree;
    end;


    -- 获取组织树第一个ID以外的下级树,如果组织树为 '1,2,3,4,5' ,第一个ID长度为1,则下级树为'2,3,5,7,3’
    -- 参数说明:参数个数:2 类型:字符型 整形 ,参数2代表第一个ID的长度


    drop function if exists get_lasttree;
    create function get_lasttree(stree varchar(500),lenid int)
    -- 设置函数的返回类型
    returns varchar(500)
    begin-- 函数头
    declare len int;
    set len=length(stree);
    if len<=lenid then
    set stree='';
    else
    set stree=right(stree,len-lenid-1);
    end if;
    return stree;
    end;


    -- 获取组织树带斜杠的格式的子树


    drop function if exists getchild_format;
    create function getchild_format(sid varchar(20)) -- 设置函数的返回类型
    returns varchar(500)
    -- RETURNS int
    begin
    declare org_id int;
    declare lentree int ;
    declare lentemptree int ;
    declare lenlasttree int;
    declare orgtree varchar(500);
    declare cursortree varchar(500);
    declare cid varchar(10);
    declare ctree varchar(500);
    declare foretree varchar(500);
    declare lasttree varchar(500);
    declare temp_tree varchar(500);
    declare lenid int;
    declare format varchar(100);
    declare format_xh varchar(100);
    declare conn varchar(100);
    declare sctree varchar(500);#用于存储顺序错误的所有带有横线标识的字符串
    declare rep_format varchar(20);
    declare temp_ctree varchar(100);
    declare temp varchar(500);
    declare format_childtree varchar(500);
    declare format_id varchar(20);
    set sctree='';

    设定节点横线字符,初始值为-,子树第一层加- ,第二层加--,依次类推

    set format='-';
    set org_id=cast(sid as SIGNED int);
    set rep_format=concat(',',format);
    set foretree='';
    select GROUP_CONCAT(id order by seq) into ctree from organizitions where organizition_id=org_id ;

    为第一层子树增加横线比如'2,3,4'变为'-2,-3,-4'' 并讲结果存储sctree

    为首节点加横线'2,3,4'变为'-2,3,4'

    set temp_ctree=concat('-',ctree);

    为剩余加横线'2,3,4'变为'-2,-3,-4'

    select REPLACE(temp_ctree,',',rep_format) into temp;
    set sctree=temp;
    select length(ctree) into lentree ;
    set lasttree=ctree;
    if lentree >0 THEN
    set cid=get_leftid(ctree);
    set foretree=org_id;
    select length(cid) into lenid;
    set lasttree=get_lasttree(ctree,lenid);
    set org_id=cast(cid as SIGNED int);
    while org_id > 0 DO
    #下一级增加一个'-'
    select GROUP_CONCAT(id order by seq ) into temp_tree from organizitions where organizition_id=org_id;

        select length(temp_tree) into lentree;    
        if lentree>0 THEN
            #循环将横线列入'-'
            set format=concat('-',format);   
            #为首节点加横线'5,6,7'变为'--5,6,7'
            set temp=concat(format,temp_tree);
            #为剩余节点增加横线'--5,6,7'变为'--5,--6,--7'
           set rep_format=concat(',',format);
           select REPLACE(temp,',',rep_format) into temp;
           #将'-2,-3,-4'和'--5,--6,--7' 组合为'-2,-3,-4,--5,--6,--7' 循环结束sctree为顺序不正确,但带层级横线的字符串
           set sctree=concat(sctree,',',temp);
           select length(lasttree) into lenlasttree;
         if lenlasttree > 0 then
           set lasttree=concat(temp_tree,',',lasttree); 
         else
           set lasttree=temp_tree;
         end if;
         select length(temp_tree) into lentemptree;
        END IF;   
        set temp_tree=lasttree; 
        #insert into test2(id,foretree,lasttree) values(org_id,foretree,lasttree);
       set  cid=get_leftid(temp_tree);    
       select length(cid) into lenid;          
       if lenid >0 THEN
          set foretree=concat(foretree,',',org_id);         
          set lasttree=get_lasttree(temp_tree,lenid);
       ELSE
          set cid='0'; 
          set orgtree=concat(foretree,',',org_id);            
       end if;         
        set org_id=cast(cid as SIGNED int);
      end while;        
    

    else
    set foretree=org_id;
    end if;
    -- return sctree;
    -- return orgtree;
    -- 替换orgtree中的ID为format_id,将sctree变为带格式的子树format_childtree
    set lasttree=orgtree;
    set org_id=get_leftid(lasttree);
    set format_childtree=org_id;
    select length(org_id) into lenid;
    set lasttree=get_lasttree(lasttree,lenid);
    select length(lasttree) into lentree;
    while lentree > 0 DO
    set org_id=get_leftid(lasttree);
    if org_id > 0 THEN
    select length(org_id) into lenid;
    set format_id=get_formatid(org_id,sctree);
    set lasttree=get_lasttree(lasttree,lenid);
    set format_childtree=concat(format_childtree,',',get_formatid(org_id,sctree));
    select length(lasttree) into lentree;
    ELSE
    set lentree=0;
    end if;
    end while ;
    return format_childtree;
    end;


    -- 更新组织树函数,执行一次存储过程,则更新orgs表,更新所有的子树和父数 调用方式:call proc_updatetree;


    drop procedure IF EXISTS proc_updatetree;
    DELIMITER $$
    CREATE PROCEDURE proc_updatetree( )

    BEGIN
    declare stree varchar(500);
    declare cid varchar(20);
    declare lenid int;
    declare org_id int;
    declare top_id int;
    declare father varchar(100);
    declare child varchar(100);
    declare child_format varchar(500);
    delete from orgs;
    set father='';
    select GROUP_CONCAT(id) into stree from organizitions ;
    select id into org_id from organizitions where organizition_id is null;
    set top_id=org_id;
    while org_id <> 0 do
    set cid = get_leftid(stree);
    set org_id=cast(cid as SIGNED int);
    select length(cid) into lenid;
    if lenid >0 then
    set stree=get_lasttree(stree,lenid);
    end if;
    set child_format= getchild_format(org_id);
    if org_id=top_id then
    set father='';
    else
    set father=getfather(cid);
    end if;
    set child=getchild(cid);
    insert into orgs(organizition_id,parent_ids,child_ids, child_ids_format) values(org_id,father,child,child_format);
    set cid = get_leftid(stree);
    select length(cid) into lenid;
    if lenid > 0 then
    set org_id=cast(cid as SIGNED int);
    else
    set org_id=0;
    end if;
    end while;
    END;


    -- 更新组织树节点 的父树


    drop function if exists getfather;
    create function getfather(sid varchar(500))
    returns varchar(500)
    begin
    declare org_id int;
    declare fid int;
    declare len int;
    declare foretree varchar(500);
    set org_id=cast(sid as SIGNED int);
    set foretree='';
    while org_id > 0 do
    select organizition_id into fid from organizitions where id=org_id ;
    if fid >0 then
    if foretree='' then
    set foretree=fid;
    ELSE
    set foretree=concat(fid,',',foretree);
    end if;
    else
    set fid=0;
    end if;
    set org_id=fid;
    end while;
    return foretree;
    end;


    -- 为orangization增加触发器,在修改、新增、删除时,调用存储过程proc_updatetree,实现
    -- 子树更新,删除触发器增加子树检查,如果该节点存在子树,则抛出信息存在子树,删除失败。


    DROP TRIGGER IF EXISTS insertorg;
    CREATE TRIGGER insertorg AFTER INSERT ON organizitions FOR EACH ROW BEGIN
    call proc_updatetree();
    END;
    DROP TRIGGER IF EXISTS updateorg;
    CREATE TRIGGER updateorg AFTER UPDATE ON organizitions FOR EACH ROW BEGIN
    call proc_updatetree();
    END;

    DROP TRIGGER IF EXISTS deleteorg;
    CREATE TRIGGER deleteorg AFTER DELETE ON organizitions FOR EACH ROW BEGIN
    If getchild(old.id) is null then
    call proc_updatetree();
    ELSE
    SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = 'Have child_tree,fail delete!';
    end if;
    END;

  • 相关阅读:
    archlinux 没有 mkfs.vfat
    fedora 14 设置 vsftpd
    USACO错误:Execution error: Your program had this runtime error: Illegal file open (/dev/tty).
    ns3介绍与安装
    1.最长平台
    打印进程号(pid)
    追踪class的成员变量
    matplotlib
    c、数组与汇编
    linux下的command
  • 原文地址:https://www.cnblogs.com/druck/p/11224829.html
Copyright © 2020-2023  润新知