通常树形结构的存储,是在子节点上存储父节点的编号来确定各节点的父子关系,例如这样的组织结构:
(资料图片)
与之对应的表数据(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操作。
标签:
- 世界热头条丨一种避免递归查询的树状数据表设计与实现
- 微资讯!云南宁蒗至永胜高速公路全线通车
- 1338名全国跑友齐聚“大美陇川”迎春奔跑感受体育魅力
- 视频 | 2022上合昆明马拉松3月26日起跑
- 世界今热点:全国首个公路联网收费系统入网检测地方标准发布
- 当前热讯:科威特西部发生原油泄漏事件 国家石油公司进入紧急状态
- 打造“不离开的工作队”
- 今日快看!部分热门中概股震荡走强 蔚来涨超8%
- 天天消息!【财经分析】欧洲银行业动荡仍未结束 实体经济将进一步受损
- 实时:社论:全球进入危机管理 做好反脆弱应迎策略
- 焦点热议:欧元区1月份贸易逆差达306亿欧元 去年全年逆差超3000亿欧元
- 实时焦点:第三届澜湄视听周国际合作论坛将在昆明举办
- 3月20日招商核心竞争力混合A净值下跌2.30%
- 【环球新要闻】涉2024年俄罗斯总统选举 俄一部门人员被要求弃用苹果手机!
- 海外宏观风险事件频发 国际金价再度站上2000美元/盎司
- 【世界聚看点】免费体检、帮办代办……昆明市首个“家庭医生门诊”开业了
- 世界快资讯:印尼将于4月1日宣布电动汽车激励措施
- 速读:瑞信最大股东沙特国家银行:投资瑞信损失超10亿美元
- 新资讯:哪个平台利息低好放款的 可以看看这些平台
- 办理信用卡哪家额度大容易通过 可以了解这几家
- 当前快看:有一种叫云南的生活|走!“克”整点舌尖上的花样
- 环球热推荐:江川区多措并举提升乡村治理水平
- 【全球热闻】英乌签署数字贸易协议助战后重建 乌克兰进口商品免关税措施延至明年
- 全球消息!昆明市五华区眠山社区为现役军人送喜报上门
- 天天快讯:瑞信百亿债券归零波及亚太 关于CoCo债你要知道的一切都在这
- 韩政府统计:晚婚成趋势 韩国40岁出头女性结婚人数连续2年高于20多岁女性
- 环球速看:黄河壶口瀑布迎来“桃花汛”
- 焦点热讯:五华区普吉街道:加强网格管理 改善辖区环境
- 快讯:2023哪家银行信用卡额度高容易申请 这几家都不错
- 世界热点评!昆明移民管理警察化身“小喇叭” 他们将两会声音带到口岸一线
- 【全球速看料】金融百家丨聂光宇:倒闭的硅谷银行会是雷曼2.0吗?
- 快资讯:为了电动化,奥迪要改名?德媒发声:“时间并不多”
- 专项扣除填报后可以撤销吗 可以作废吗
- 全球即时看!加拿大对华钢管桩发起第二次双反日落复审立案调查
- 每日聚焦:中国银行大额存单多久发行一次 答案如下
- 女大学生在昆发出“SOS”家长异地报警原来虚惊一场
- 昆明市生态环境局西山分局召开2023年生态环境保护工作会议
- 全球快资讯:调查:近7成日企提高今春入职应届生起薪 游戏行业涨薪幅度显著
- 天天热点评!美媒:美联储早在2019年就对硅谷银行风险管理系统发出警告
- 世界热议:昆明东川:“手牵手”共创卫生乡镇·“心连心”共建绿美阿旺
- 【世界报资讯】【视频】戍边民警手写妻子生日“请假条”,警嫂:批准!
- 异地就医备案后在参保地还能用医保吗 最新规定是这样的
- 今亮点!上证i播报:3月20日欧洲股市开盘涨跌不一
- 啥子平台借款会马上放款 这几个都不错
- 全球今日讯!农业银行尊然白金卡年费是多少 年费标准如下
- 头条焦点:日本央行:仍需维持宽松货币政策
- 每日热讯!中国银行信用卡免年费政策是什么 具体情况如下
- 昆明东川:党建引领生态绿 绘就生态宜居新画卷
- 环球速递!声动中国丨“给你们看看什么叫幸福”
- 正规网上借钱平台有哪些 在哪里借钱不用担心
- 头条焦点:美联储等六家央行将通过美元互换协议提高流动性 市场恐慌会停止吗?丨就市论市
- 全球要闻:中银e贷扣款时间什么时候 官方规定如下
- 7日年化1.8% 1万元一天利息多少 计算方式如下
- 环球热推荐:石屏:“稻蟹养殖”探索绿色生态农业发展新模式
- 世界热文:2023年“昌宁邀您来采茶”主题活动启动
- 要闻:各大银行信用卡申请条件是什么 哪些信用卡好用
- 【当前独家】美联储联手五大央行出手!
- 世界快看点丨建行线上提前还款申请不了怎么回事 视情况而定
- 【天天快播报】热搜!韩国40出头新娘人数比20岁还多,连续两年出现该现象!去年结婚人数创53年以来新低
- 开干吧2023!爱采购领跑计划高燃进行,与中小企业同呼吸共命运
- 法国天芮60周年品牌盛典璀璨启幕,发布全新战略,开启全新篇章
- 热点在线丨广发信用卡利息是怎么算的 为什么会有利息
- 韩国首枚民营火箭在巴西发射升空
- 天天热文:车祸有一半责任可以报医保吗 情况是这样的
- 【天天速看料】香港金管局:瑞士信贷旗下在港公司将照常营业
- 全球短讯!近视手术可以用医保报销吗 情况是这样的
- 当前简讯:【新华财经调查】日本十年人才政策成效不佳 4月新政依然面临挑战
- 交通银行信用卡一年刷几次免年费 最新年费收取规则如下
- 世界观天下!招商信用卡分期还款划算吗 视情况而定
- 2023世界童模大赛全球启动
- 当前观点:瑞银收购瑞信落定 美国地区银行依旧前途未卜 谁来接手?
- 每日动态!为什么不建议个人交养老保险 有以下几大原因
- 全球微资讯!小程序手势 打开半屏新姿势
- 美联储联合五大央行加码美元互换协议,稳定流动性
- 天天热议:统计:韩国近50万年轻人不找工作单纯休息
- 世界微动态丨新加坡金管局:瑞信在新加坡的业务将继续运营
- 即时焦点:邮政信用卡到期后会自动寄新卡片吗 银行是这么回应的
- 世界热议:报告:中国和加拿大在清洁技术领域有较大合作空间和潜力
- ETF基金可以定投吗 专业人士这样说
- 自己缴社保和企业缴社保的比例是多少?自己缴社保和企业缴社保退休后工资有什么区别吗?
- 南京公积金贷款首付比例怎么定?公积金贷款利率是多少?
- 在异地就医如何备案?异地就医备案后刷医保卡怎么操作?
- 股票如何成交?股票委托失败的原因是什么?
- 抖音月付额度5万算高吗?如何提高抖音月付额度?
- 重大疾病的人还能买保险吗?重疾险包括什么?
- 可转债委托提示废单的原因有哪些?无法买入可转债是什么原因?
- 可转债的交易时间是几点?可转债委托卖出成交规定是什么?
- 用公积金可以贷款多少钱?用公积金贷款有什么好处?
- ETF基金能套利吗?ETF套利的方法有哪些?
- 环球精选!经合组织预计2023年全球经济增长2.6%
- 天天简讯:出境游扩容复苏显著,上海赴马来西亚首发团“接福利”
- 环球焦点!2023版熊猫金币30克今天报价(2023年03月20日)
- 异地就医备案后可以刷医保卡吗 看这篇就够了
- 自己缴社保和企业缴社保退休后拿的退休工资一样吗 答案如下
- 各大银行提前还款时间规定是什么 是怎么规定
- 【天天热闻】普洱镇沅八大茶区春茶陆续开采
- 香港金管局:瑞士信贷在港业务照常运行 未构成重大风险
- 基金卖出为什么还在亏?基金出现亏损怎么解决?
- 车辆意外被火烧了保险给赔吗 视情况而定
- 【世界时快讯】南京公积金贷款最多可以贷多少 规定是这样的