通常树形结构的存储,是在子节点上存储父节点的编号来确定各节点的父子关系,例如这样的组织结构:
与之对应的表数据(department):
部门表结构(department)
(资料图)
id部门编号name部门名称level所在树层级parent_id上级部门编号问题来了
这样的方式很不错,可以很直观的体现各个节点之间的关系,通常可以满足大多数需求。但是当业务需求变得多了,数据量庞大了,这样的方式就不再适合用于生产。
例如:PM加了以下需求:
查出指定部门下所有子孙部门查询子孙部门总数判断节点是否叶子节点查出所有子孙部门
使用指定部门编号,一层一层使用递归往下查,可能是多数人会想到的方法。尽管在mysql8.0支持了 cte(公共表表达式),递归效率比传统递归方式有明显提升,但是查询效率仍会随着部门树层级深度的提高而变差。
另外一种方法,一次性查出所有数据,放入内存中处理(数据量少时,可以选用。数据量多,不怕挨打的人也可以选这种)~
查询子孙部门总数
递归查询每一层的数量,最后相加。
判断是否叶子节点
方法1:可以加字段isLeaf的方式,来表示这个节点是否是叶子节点。
方法2:直接通过查询parent_id=当前id的count是否大于0,大于0表示不是叶子节点,等于0表示为叶子节点。
在日常中,可能会经常使用上述类似方法去解决类似的问题,但我觉得这样的方法在效率上不是最优解。于是乎开始查找更好的方案去解决这些问题。
| 要不试试这个方法?
直到后面查到国外一博客中,见到了所谓的《改进后的先序树遍历》文章(天哪,竟然是一篇2003年发表的文章)~
他具体是怎么做的呢?
还是回到刚刚的组织架构
我们从根节点开始,给董事长左值设为1,下级部门总经理左值设为2,以此类推地沿着边缘开始遍历,给每个节点加上左值,遇到叶子节点处给节点加上右值,再继续向上沿着边缘继续遍历,遍历结束回到根节点右侧,你将得到类似这样的结构。
遍历完后每一个节点都有与之对应的左右值。这个时候可以去除parent_id字段,添加lft,rgt,来存储左右值。
数据和结构准备完毕,我们来试试操作解决上面的需求~
查出所有子孙部门
根据当前表结构的规律,可以发现,要想查出所有子孙部门,只要查左值在 被查寻部门的左\右数之间的节点,查出来都是他的子节点。例如:查询行政总监的所有子部门,行政总监的左右数是9和18,因此只需要用9和18做lft字段的between查询,查询出的结果就是【被查部门本身数据和所有子孙部门】;
SET@lft:=9;SET@rgt:=18;SELECT*FROMdepartmentWHERElftBETWEEN@lftAND@rgtORDERBYlftASC;/*例子中用BETWEEN将被查部门本身也查了出来。实际中可以用大于小于*/完美~查询子孙部门总数
到这里可能会说,需求1都解决了,查总数自然也就解决了,直接上select count就可以了,确实没有错,但是没有那个必要,因为有个简单公式可以直接计算。
公式:总数 = (右值 - 左值 - 1) / 2
例如:
行政总监的子孙部门数=(18-9-1)/2=4董事长的子孙部门数=(20-1-1)/2=9会计的子部门数=(14-13-1)/2=0可以数数看,确实没错哦~判断是否叶子节点
通过有了上述计算公式算总数的经验后,现在判断是否叶子节点,有的小伙伴已经知道了怎么做,那就是:
右值 - 1 == 左值那他就是叶子节点,或者左值 + 1 == 右值那他就是叶子节点,反之则不是叶子节点。
例如:
设计部,5 - 1 == 4,因此他是叶子节点。
董事长,20 - 1 != 1,因此他不是叶子节点。
至此已经完美的解决了上述需求问题,接下来再尝试一下业务的基本操作。
其他基本操作
新增部门
当新增一个部门时,需要对新增节点位置的后续边缘进行加2操作,因为每一个节点有左右两个数值。这个操作通常需要放到事务中进行处理。例如:在研发部门下添加一个新部门:
对应sql:
SET@lft:=7;/*新部门的左值*/SET@rgt:=8;/*新部门的左值*/SET@level:=5;/*新部门的层级*/begin;/*将插入的后续边缘的节点左右数+2*/UPDATEdepartmentSETlft=lft+2WHERElft>@lft;UPDATEdepartmentSETrgt=rgt+2WHERErgt>=@lft;/*插入数据*/INSERTINTOdepartment(name,lft,rgt,level)VALUES("新部门",@lft,@rgt,level);/*新增影响行数为0时,必须回滚*/commit;/*rollback;*/删除部门
删除部门与新增部门类似,不同的是需要对删除节点的后续边缘节点减2操作。例如:删除刚刚添加的新部门:
对应sql
SET@lft:=7;/*要删除的节点左值*/SET@rgt:=8;/*要删除的节点右值*/begin;UPDATEdepartmentSETlft=lft-2WHERElft>@lft;UPDATEdepartmentSETrgt=rgt-2WHERErgt>@lft;/*删除节点*/DELETEFROMdepartmentWHERElft=@lftANDrgt=@rgt;/*删除影响行数为0时,必须回滚*/commit;/*rollback*/查询直接子部门
查询某部门的直接子部门(即不包含孙子部门),例如:查询总经理下的直接子部门。正常需要返回产品部和行政总监
对应的sql
SET@level:=2;/*总经理的level*/SET@lft:=2;/*总经理的左值*/SET@rgt:=19;/*总经理的右值*/SELECT*FROMdepartmentWHERElft>@lftANDrgt<@rgtANDlevel=@level+1;查询祖链路径
查询某部门的祖链路径。例如:查询产品部的祖链路径,正常需要返回董事长,总经理
SET@lft:=3;/*产品部左值*/SET@rgt:=8;/*产品部右值*/SELECT*FROMdepartmentWHERElft<@lftANDrgt>@rgtORDERBYlftASC;树形数据展示(JS示例)
letlist=[//模拟sql查出来的列表。{id:1,name:"root",lft:1,rgt:8,level:1},{id:2,name:"child",lft:2,rgt:7,level:2},{id:3,name:"grandson",lft:3,rgt:4,level:3},{id:4,name:"grandson2",lft:5,rgt:6,level:3}];letrights=[]/*类似于一个栈结构(后进先出)*/letmp={}//list.sort((a,b)=> a.lft - b.lft)//如果你在sql中没有进行排序,需要在这里给他排序。list.forEach(item=>{if(rights.length>0){while(rights[rights.length-1]{let_tree=[];_list.forEach(item=>{if(item.parent_id==parent_id){letchilds=recursive(_list,item.id)_tree.push({...item,children:childs.length>0?childs:(item.isLeaf?null:[])})}})return_tree}console.log(recursive(list)) 完结
在我目前看来,这个方法的唯一缺点就是,每一次的新增或删除,操作节点的后续边缘走到的节点都要加/减2操作。
标签:
-
一种避免递归查询的树状数据表设计与实现-全球要闻
通常树形结构的存储,是在子节点上存储父节点的编号来确定各节点的父子关系,例如这样的组织结构:
-
特高压工程迎建设大年,月内近10家上市公司中标国家电网大单_世界快看
App3月17日消息,今年以来,特高压输电通道等新型电力系统的建设任务加速落地,特高压建设在经历2022年的放缓后,有望在2023年迎来提速。此前
-
吃蛋白粉的不良反应_吃蛋白粉的坏处 全球聚焦
1、蛋白粉是一种营养食品。2、经常吃蛋白粉可以增强人体免疫力,促进新陈代谢,但也有其副作用。3、主要是因为对于老年患者来
-
【全球快播报】你说过我信过小说_你说过我信过
1、歌名:你说过。2、我信过 演唱:渔圈&C蓝 作词:渔圈&C蓝 作曲;渔圈&C蓝 渔圈: 最后你始终要走
-
焦点观察:CBA公告:同意新疆广汇复赛
CBA微博消息,2023年3月15日CBA公司召开临时股东会审议并表决,同意新疆广汇篮球俱乐部恢复参加2022-2023赛季CBA联赛。公告全文如下: 为使中
-
微速讯:2023海南省公务员省考笔试成绩查询时间
海南省公务员省考笔试成绩查询查询时间:3月16日起可以查查询入口:海南省考试录用公务员网上报名管理系统分数线笔试合格分数线划定如下:市(
-
戴伟浚晒热身赛视频:身体状态越来越好下一站新西兰⚽️ 环球热议
戴伟浚晒热身赛视频:身体状态越来越好下一站新西兰⚽️,戴伟浚,新西兰,下一站,阿联酋,中国足球,足球竞赛,英国足球,土库曼斯坦,足球运动员
-
一品红:中信证券、国海证券等多家机构于3月13日调研我司_天天聚看点
2023年3月16日一品红(300723)发布公告称中信证券陈竹、国海证券周小刚、德邦证券陈铁林、华创证券刘浩、中泰证券祝嘉琦、红杉资本、中信建投
-
【闽商杂志】喜报!安踏荣获多项国际大奖!
近日,安踏集团作为可持续发展理念的积极践行者,在ESG和投资者关系方面备受认可,接连获得在“福布斯中国2023年度ESG
-
草莓香甜采摘乐
近日,大通区孔店乡河沿村的草莓大棚里,迎来一批前来采摘、踏青的市民。进入3月天气转暖,各草莓园迎来采摘旺季,不少市民趁着
-
今头条!纳思达(002180):3月15日北向资金增持139.4万股
3月15日北向资金增持139 4万股纳思达。近5个交易日中,获北向资金增持的有4天,累计净增持379 09万股。近20个交易日中,获北向资金增持的有14
-
盖瑞·安德森
1、盖瑞·约瑟夫·安德森(GarretJosephAnderson,1972年7月30日-)生于加利福尼亚州洛杉
-
马应龙麝香痔疮膏怎么用_马应龙麝香痔疮膏怎么用_天天速读
1、马应龙麝香痔疮膏是治疗痔疮的常用药物之一,由人工麝香、人工牛黄、珍珠、炉甘石、硼砂、冰片、琥珀组成。2、具有清热利湿
-
前沿资讯!万傲瑞达v6000_v6000hdv
1、长时间没使用应该是受潮了不能开机。以上就是【万傲瑞达v6000,v6000hdv】相关内容。
-
(新华全媒+)花式饮茶“新姿”展现新消费活力
(新华全媒+)花式饮茶“新姿”展现新消费活力
-
门店战略升级与业务调整 盒马南京首店将于3月19日停止营业
门店战略升级与业务调整盒马南京首店将于3月19日停止营业
-
简历名称如何命名最好_简历名称该写什么
1、要想让你的简历可以吸引HR的眼光而且又容易找的话,简历名称千万不要写这几种:“个人简历”、“我的简历”、“简历”、“
-
湖南对养老机构服务收费实行分类管理
近日印发的《湖南省养老机构服务收费管理办法》(简称《办法》)明确,养老机构服务收费实行政府指导价、市场调节价两类管理,收
-
利物浦逆转皇马六样板:曼联热刺教学 巴黎巴萨苦主_新要闻
如果说有哪支球队能够在欧冠中挽回三球的劣势,那一定是利物浦。红军最知道如何在最辉煌的阶段起死回生,2005年的伊斯坦布尔奇迹就是个最好的
-
天天视讯!非居民个人所得税税率表(人所得税税率表)
1、2020年我们国家规定的个人所得税的起征点是5000元。2、工资范围在1-5000元之间的,包括5000元,适用个人所得税税率为0%。3、2、工资范围在50
-
世界动态:一切随缘原唱_一切随缘
1、很认真的看了楼上两位善知识的回帖,你们能对一个初来此地的陌生人不怕麻烦如理如法的回答,很感动 我
-
当前最新:太离谱!男子拄拐开车,一查竟是无证加醉驾
经调查,男子郭某某系无证驾驶机动车,医院抽血化验结果为165 8mg 100ml
-
环球快看点丨绿色食品的含义视频_绿色食品的含义
一、题文绿色食品标志有什么含义?二、解答绿色食品标志图形由三部分构成:上方的太阳、下方的叶片和蓓蕾,象征自然生态;标志图
-
三门峡市首例“带押过户”落地
三门峡市首例“带押过户”落地
-
03月14日12时云南迪庆疫情数据 阳了以后为什么会腰疼?应该怎么办?-今日热文
03月14日12时云南迪庆疫情数据阳了以后为什么会腰疼?应该怎么办?以下为详情!一、03月14日12时迪庆疫情数据概览
-
每日视讯:阳泉新型冠状病毒肺炎疫情:3月14日阳泉疫情最新消息今天数据统计情况通报
阳泉新型冠状病毒肺炎疫情:3月14日阳泉疫情最新消息今天数据统计情况通报,截至3月14日11时01分阳泉疫情数据统计情况
-
世界观点:美参议院银行委员会成员:硅谷银行破产要归咎于管理不善和监管不力
美参议院银行委员会成员:硅谷银行破产要归咎于管理不善和监管不力:美国参议院银行委员会成员Hagerty表示,硅谷银行破产一事要归咎于管理不善
-
天天最资讯丨上古卷轴5 灵魂石_上古卷轴5 跳出
上古卷轴5灵魂石,上古卷轴5跳出这个很多人还不知道,现在让我们一起来看看吧!1、第一,从一个以前一开始还没做过任何任
-
下边腥臭味怎么办_下面腥臭味是什么回事
1、当外阴和白带有腥味时,提示可能有阴道炎症状。建议去医院妇科挂号做白带检查,确定白带属于哪种阴道炎,可以插阴道药。如果
-
肥西县上派镇三岗村开展“爱的家园 一起呵护”植树节主题活动
肥西县上派镇三岗村开展“爱的家园一起呵护”植树节主题活动