背景

公司的一个业务系统中有区域表,整个区域是一个树结构,为了方便根据某一父节点查询所有叶子节点,提供了一个额外的字段path,按照分隔符存储了从根节点到当前节点的总路径。

表结构如下:

create table t_area
(
area_id varchar(32) not null comment '主键' primary key,
area_pid varchar(32) null comment '父级区域ID',
area_name varchar(30) null comment '区域名称',
level varchar(2) null comment '层级 从1开始',
external_name varchar(30) null comment '对外名称',
flag varchar(3) null comment '特殊标记 0=没有标记 1=特殊入门',
path varchar(200) null
)
comment '区域位置表';

比如,有以下路径:

  • A楼-13层-1301室
  • A楼-13层-1302室
  • A楼-13层-1303室

那么,

  • 在1301的path字段存储为:A楼id#13层id#1301id
  • 在1302的path字段存储为:A楼id#13层id#1302id
  • 在1303的path字段存储为:A楼id#13层id#1303id

目前的需求是,需要查询给定叶子节点的完整路径名称,但是待查询的表中只存储了叶子节点的area_id

有两种方式可以实现:

  1. 写一个SQL查询出叶子节点id,对应的path,在Java层面,按照#切割字符串,得到每一层的area_id,再用SQL查询出area_id对应的area_name,拼接好返回
  2. 在MySQL中实现一个自定义函数,传入叶子节点的id,即可获取完整路径名称。

如果使用第二种方式,该业务SQL就变得很简单,考虑用函数实现。

函数实现

CREATE DEFINER=`sgsv2`@`%` FUNCTION `getFullArea`(`areaId` varchar(50)) RETURNS varchar(50) CHARSET utf8
BEGIN
set @area_id=areaId;
-- select @area_id;
select path from t_area where area_id = @area_id limit 1 into @path;
-- select @path;
SET @i=2;
SET @count=(LENGTH(@path)-LENGTH(REPLACE(@path ,'#',''))) + 1;
set @returnStr="";
-- select @count; WHILE @i <= @count
DO
set @areaTmpId=(SUBSTRING_INDEX(SUBSTRING_INDEX(@path,'#',@i),'#',-1));
-- select @areaTmpId;
select area_name from t_area where area_id = @areaTmpId into @areaTmpName;
-- select @areaTmpName; if @i > 2 Then
set @returnStr=concat(@returnStr,'-',@areaTmpName);
else
set @returnStr=concat(@returnStr,@areaTmpName);
end if; -- set @returnStr=concat(@returnStr,'-',@areaTmpName);
-- select @returnStr;
SET @i=@i+1;
END WHILE; -- select @returnStr; RETURN @returnStr;
END

要点:获取path后,如何遍历获取每层的area_id?

我这里的实现是,先用下面的语句,获取总area_id的个数

SET @count=(LENGTH(@path)-LENGTH(REPLACE(@path ,'#',''))) + 1;

根据获得的count数进行遍历,在遍历中获取每一个area_id,关键语句如下:

set @areaTmpId=(SUBSTRING_INDEX(SUBSTRING_INDEX(@path,'#',@i),'#',-1));

最后使用concat函数拼接得到最终的结果

set @returnStr=concat(@returnStr,'-',@areaTmpName);

技巧:可以使用存储过程来调试

在函数中, 无法像存储过程一样,使用select @变量名来调试,所以我先把函数主题复制到一个存储过程中,这样就可以调试了!

MySQL函数-根据子节点查询所有父节点名称的更多相关文章

  1. Treeview控件如何获得子节点的所有父节点的名称

    Delphi或c++ 的treeview控件,比如一个节点上面有个父节点,这个父节点上面还有一个父节点,如何获得这两个父节点的名字呢?请给出实现代码 先定义一个nodevarnode:TTreeNod ...

  2. T-Sql 递归查询(给定节点查所有父节点、所有子节点的方法)

    -- 查找所有父节点with tab as( select Type_Id,ParentId,Type_Name from Sys_ParamType_V2_0 where Type_Id=316-- ...

  3. [SQL]T-Sql 递归查询(给定节点查所有父节点、所有子节点的方法)

    T-Sql 递归查询(给定节点查所有父节点.所有子节点的方法)   -- 查找所有父节点with tab as( select Type_Id,ParentId,Type_Name from Sys_ ...

  4. Element ui tree树形控件获取当前节点id和父节点id

    低版本Element ui tree树形控件获取当前节点id和父节点id的方法:点击查看 最新版本Element ui tree树形控件获取当前节点id和父节点id教程: 1.找到node_modul ...

  5. mysql 函数获取子节点

    DELIMITER $$ USE `topsale`$$ DROP FUNCTION IF EXISTS `getShopIdByUserId`$$ CREATE DEFINER=`root`@`%` ...

  6. 你真的会玩SQL吗?查询指定节点及其所有父节点的方法

    --查询ID = '009'的所有父节点 ' ;WITH T AS ( SELECT ID , PID , NAME FROM TB WHERE ID = @ID UNION ALL SELECT A ...

  7. Rafy 中的 Linq 查询支持(根据聚合子条件查询聚合父)

    为了提高开发者的易用性,Rafy 领域实体框架在很早开始就已经支持使用 Linq 语法来查询实体了.但是只支持了一些简单的.常用的条件查询,支持的力度很有限.特别是遇到对聚合对象的查询时,就不能再使用 ...

  8. ztree删除某个节点下的全部子节点后,父节点图标还是文件夹

    <script type="text/javascript"> //删除节点 zTree.removeNode(treeNode); //获取删除节点的父节点 var ...

  9. easyui Tree模拟级联勾选cascadeCheck,节点选择,父节点自动选中,节点取消,父节点自动取消选择,节点选择,所有子节点全部选择,节点取消,所有子节点全部取消勾选

    最近项目中用到easyui tree,发现tree控件的cascadeCheck有些坑,不像miniui 的tree控件,级联勾选符合业务需求,所以就自己重新改写了onCheck事件,符合业务需求.网 ...

  10. 记录JS如何使用广度遍历找到节点的所有父节点

    我们在实际的工作业务场景中经常遇到这样的场景,求取树数据中某个节点的父亲节点以及所有的父亲节点,这样的场景下不建议使用深度遍历,使用广度遍历可以更快找到. 1.案例解说 比如树的长相是这样的: 树的数 ...

随机推荐

  1. 浅谈Spring Data ElasticSearch

    Spring Data Spring Data 帮助我们避免了一些样板式代码,比如我们要定义一个接口,可以直接继承接口ElasticSearchRepository接口,这样Spring Data就帮 ...

  2. JVM监控工具使用

    1. 描述 ​ 程序在开发过程中,有可能会发生CPU飙高.内存溢出等问题或系统在后期调优阶段,不可避免的要监控JVM情况,JDK自带的Jconsole监控工具,结合Tomcat使用非常方便,占用内存小 ...

  3. Qml 中实现任意角为圆角的矩形

    [写在前面] 在 Qml 中,矩形(Rectangle)是最常用的元素之一. 然而,标准的矩形元素仅允许设置统一的圆角半径. 在实际开发中,我们经常需要更灵活的圆角设置,例如只对某些角进行圆角处理,或 ...

  4. MySQL如果数据存在则更新,不存在则插入

    如果数据存在则更新,不存在则插入,MySQL有duplicate.replace into.replace三种方式如何更新数据? insert ignore into 又是如何插入数据的呢? 准备表和 ...

  5. 3090 cuda环境配置杂记

    实验室新配了3090的电脑,cuda环境配置上出了些问题,百度很久才找到解决方法,因此记录下来. 主要参考:(6条消息) 服务器Linux环境配置cuda(非管理员)_@@Lynn的博客-CSDN博客 ...

  6. TensorFlow2入门与实践--CNN

    卷积神经网络CNN CNN原理 关于CNN的原理本文使用代码的方式来直观理解卷积中各个操作过程. 卷积 卷积层是CNN的核心组件,通过可学习的卷积核在输入特征图上进行滑动窗口操作.每个位置上,卷积核与 ...

  7. 回顾我的软件开发经历:开发DAB

    背景介绍 DAB(Device Automation Bus)是一种基于 MQTT 通信的轻量级协议,主要用于连接客厅中的消费电子产品(如智能电视和游戏机),并实现自动化测试.由于设备认证需要支持 D ...

  8. Java中的Scanner、BufferedReader 和 StreamTokenizer

    1. Scanner 的使用与分析 简介: Scanner 是 Java 中一个用于解析原始类型(如 int.double 等)和字符串的类.它通常从输入流中逐个读取数据并进行解析,支持多种分隔符的使 ...

  9. [源码分析] Facebook如何训练超大模型--- (5)

    [源码分析] Facebook如何训练超大模型--- (5) 目录 [源码分析] Facebook如何训练超大模型--- (5) 0x00 摘要 0x01 背景 0x02 思路 2.1 学习建议 2. ...

  10. 优化-iceberg调参优化

    一.建表优化 1.iceberg表支持更新操作. 文档:https://iceberg.apache.org/docs/latest/configuration/ 功能描述:因v1只支持insert, ...