MySQL 查询树结构方式

目录
  • MySQL 查询树结构
    • 1. 关于树结构
    • 2. MySQL自定义函数的方式
      • 2.1 创建测试数据
      • 2.2 获取 某节点下所有子节点
      • 2.3 获取 某节点的所有父节点
    • 3. Oracle数据库的方式
    • 4. 程序代码递归的方式构建树
    • 5. 通过hashMap,只需要遍历一次
  • MySQL 查询带树状结构的信息
    • 在Oracle中可以直接用下面的语法可以进行直接查询
    • 但是在Mysql中是没有这个语法的

MySQL 查询树结构

1. 关于树结构

此类结构的数据,通常需要表结构中含有id 、parentId等自关联字段,有时为了提高查询效率还可增加更多冗余字段,如index,index的值为所有父级目录的id字符串集合。

关于树结构数据的组装,常见的写法是在程序中通过递归的方式去构建出一颗完整的树,单纯通过sql的方式其实并不常用,下面分别给出两种方式的例子。

2. MySQL自定义函数的方式

什么是MySQL自定义函数:聚合函数,日期函数之类的都是MySQL的函数,此处我们定义的函数可同他们一样使用,不过只能在定义的数据库中使用,自定义函数和存储过程类似,不同的是,函数只会返回一个值,不允许返回一个结果集。

2.1 创建测试数据

CREATE TABLE `tree`  (
  `id` bigint(11) NOT NULL,
  `pid` bigint(11) NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `tree` VALUES (1, 0, '中国');
INSERT INTO `tree` VALUES (2, 1, '四川省');
INSERT INTO `tree` VALUES (3, 2, '成都市');
INSERT INTO `tree` VALUES (4, 3, '武侯区');
INSERT INTO `tree` VALUES (5, 4, '红牌楼');
INSERT INTO `tree` VALUES (6, 1, '广东省');
INSERT INTO `tree` VALUES (7, 1, '浙江省');
INSERT INTO `tree` VALUES (8, 6, '广州市');

2.2 获取 某节点下所有子节点

CREATE FUNCTION `GET_CHILD_NODE`(rootId varchar(100))
RETURNS varchar(2000)
BEGIN
DECLARE str varchar(2000);
DECLARE cid varchar(100);
SET str = '$';
SET cid = rootId;
WHILE cid is not null DO
    SET str = concat(str, ',', cid);
    SELECT group_concat(id) INTO cid FROM tree where FIND_IN_SET(pid, cid);
END WHILE;
RETURN str;
END

调用自定义函数

select * from tree where FIND_IN_SET(id, GET_CHILD_NODE(2));

2.3 获取 某节点的所有父节点

CREATE FUNCTION `GET_PARENT_NODE`(rootId varchar(100))
RETURNS varchar(1000)
BEGIN
DECLARE fid varchar(100) default '';
DECLARE str varchar(1000) default rootId;   

WHILE rootId is not null do
    SET fid =(SELECT pid FROM tree WHERE id = rootId);
    IF fid is not null THEN
        SET str = concat(str, ',', fid);
        SET rootId = fid;
    ELSE
        SET rootId = fid;
    END IF;
END WHILE;
return str;
END

调用自定义函数

select * from tree where FIND_IN_SET(id, GET_PARENT_NODE(5));

3. Oracle数据库的方式

只需要使用start with connect by prior语句即可完成递归的树查询,详情请自己查阅相关资料。

4. 程序代码递归的方式构建树

这里我就不给出完整代码了,递归的方式很简单,就是先查出所有树节点,然后通过一个TreeNode类中的add方法递归把所有子节点给加进来。核心代码如下:

public class TreeNodeDTO {

    private String id;
    private String parentId;
    private String name;
    private List<TreeNodeDTO> children = new ArrayList<>();
    public void add(TreeNodeDTO node) {
        if ("0".equals(node.parentId)) {
            this.children.add(node);
        } else if (node.parentId.equals(this.id)) {
            this.children.add(node);
        } else {
         	//递归调用add()添加子节点
            for (TreeNodeDTO tmp_node : children) {
                tmp_node.add(node);
            }
        }
    }
 }

5. 通过hashMap,只需要遍历一次

就可以完成树的生成:五星推荐

List<TreeNodeDTO> list = dbMapper.getNodeList();
ArrayList<TreeNodeDTO> rootNodes = new ArrayList<>();
Map<Integer, TreeNodeDTO> map = new HashMap<>();
for (TreeNodeDTO node :list) {
    map.put(node.getId(), node);
    Integer parentId = node.getParentId();
    // 判断是否有父节点 (没有父节点本身就是个父菜单)
    if (parentId.equals('0')){
        rootNodes.add(node);
        // 找出不是父级菜单的且集合中包括其父菜单ID
    } else if (map.containsKey(parentId)){
        map.get(parentId).getChildren().add(node);
    }
}

MySQL 查询带树状结构的信息

在Oracle中有函数应用直接能够查询出树状的树状结构信息,例如有下面树状结构的组织成员架构,那么如果我们想查其中一个节点下的所有节点信息

在Oracle中可以直接用下面的语法可以进行直接查询

START WITH CONNECT BY PRIOR

但是在Mysql中是没有这个语法的

而如果你也是想要查询这样的数据结构信息该怎么做呢?我们可以自定义函数。我们将上面的信息初始化信息进数据库中。首先先创建一张表用于存储这些信息,ID为存储自身的ID信息,PARENT_ID存储父ID信息

CREATE TABLE `company_inf` (
  `ID` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `NAME` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `PARENT_ID` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL
)

然后将图中的信息初始化表中

INSERT INTO company_inf VALUES ('1','总经理王大麻子','1');
INSERT INTO company_inf VALUES ('2','研发部经理刘大瘸子','1');
INSERT INTO company_inf VALUES ('3','销售部经理马二愣子','1');
INSERT INTO company_inf VALUES ('4','财务部经理赵三驼子','1');
INSERT INTO company_inf VALUES ('5','秘书员工J','1');
INSERT INTO company_inf VALUES ('6','研发一组组长吴大棒槌','2');
INSERT INTO company_inf VALUES ('7','研发二组组长郑老六','2');
INSERT INTO company_inf VALUES ('8','销售人员G','3');
INSERT INTO company_inf VALUES ('9','销售人员H','3');
INSERT INTO company_inf VALUES ('10','财务人员I','4');
INSERT INTO company_inf VALUES ('11','开发人员A','6');
INSERT INTO company_inf VALUES ('12','开发人员B','6');
INSERT INTO company_inf VALUES ('13','开发人员C','6');
INSERT INTO company_inf VALUES ('14','开发人员D','7');
INSERT INTO company_inf VALUES ('15','开发人员E','7');
INSERT INTO company_inf VALUES ('16','开发人员F','7');

例如我们想要查询研发部门经理刘大瘸子下的所有员工,在Oracle中我们可以这样写

  SELECT *
  FROM T_PORTAL_AUTHORITY
  START WITH ID='1'
  CONNECT BY PRIOR ID = PARENT_ID

而在Mysql中我们需要下面这样自定义函数

CREATE FUNCTION getChild(parentId VARCHAR(1000))
RETURNS VARCHAR(1000)
BEGIN
    DECLARE oTemp VARCHAR(1000);
    DECLARE oTempChild VARCHAR(1000);
    SET oTemp = '';
    SET oTempChild =parentId;
    WHILE oTempChild is not null DO
        IF oTemp != '' THEN
            SET oTemp = concat(oTemp,',',oTempChild);
        ELSE
            SET oTemp = oTempChild;
        END IF;
        SELECT group_concat(ID) INTO oTempChild FROM company_inf where parentId<>ID and FIND_IN_SET(parent_id,oTempChild)>0;
    END WHILE;
RETURN oTemp;
END

然后这样查询即可

SELECT * FROM company_inf WHERE FIND_IN_SET(ID,getChild('2'));

此时查看查询出来的信息就是刘大瘸子下所有的员工信息了

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • MySQL多层级结构-树搜索介绍

    基本上在每个系统中都有那么几张表是自关联父子关系的结构.往往有很多人都是使用pid来做关联.在刚进入IT行业时使用CAKEPHP框架编写WEB的时候,使用它里面的一个ACL plugin实现权限管理的时候.发现一个表结构硬是不明白是怎么回事.具体表结构如下: CREATE TABLE acos ( id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, parent_id INTEGER(10) DEFAULT NULL, model VARCHAR(2

  • Mysql树形递归查询的实现方法

    前言 对于数据库中的树形结构数据,如部门表,有时候,我们需要知道某部门的所有下属部分或者某部分的所有上级部门,这时候就需要用到mysql的递归查询 最近在做项目迁移,Oracle版本的迁到Mysql版本,遇到有些oracle的函数,mysql并没有,所以就只好想自定义函数或者找到替换函数的方法进行改造. Oracle递归查询 oracle实现递归查询的话,就可以使用start with ... connect by connect by递归查询基本语法是: select 1 from 表格 st

  • MySQL递归查询树状表的子节点、父节点具体实现

    简介:mysql5.0.94版本,该版本以及较高级的版本(5.5.6等等)尚未支持循环递归查询,和sqlserver.oracle相比,mysql难于在树状表中层层遍历的子节点.本程序重点参考了下面的资料,写了两个sql存储过程,子节点查询算是照搬了,父节点查询是逆思维弄的. 表结构和表数据就不公示了,查询的表user_role,主键是id,每条记录有parentid字段(对应该记录的父节点,当然,一个父节点自然会有一个以上的子节点嘛) 复制代码 代码如下: CREATE FUNCTION `g

  • MySQL实现树状所有子节点查询的方法

    本文实例讲述了MySQL实现树状所有子节点查询的方法.分享给大家供大家参考,具体如下: 在Oracle 中我们知道有一个 Hierarchical Queries 通过CONNECT BY 我们可以方便的查了所有当前节点下的所有子节点.但很遗憾,在MySQL的目前版本中还没有对应的功能. 在MySQL中如果是有限的层次,比如我们事先如果可以确定这个树的最大深度是4, 那么所有节点为根的树的深度均不会超过4,则我们可以直接通过left join 来实现. 但很多时候我们无法控制树的深度.这时就需要

  • MySQL 查询树结构方式

    目录 MySQL 查询树结构 1. 关于树结构 2. MySQL自定义函数的方式 2.1 创建测试数据 2.2 获取 某节点下所有子节点 2.3 获取 某节点的所有父节点 3. Oracle数据库的方式 4. 程序代码递归的方式构建树 5. 通过hashMap,只需要遍历一次 MySQL 查询带树状结构的信息 在Oracle中可以直接用下面的语法可以进行直接查询 但是在Mysql中是没有这个语法的 MySQL 查询树结构 1. 关于树结构 此类结构的数据,通常需要表结构中含有id .parent

  • mysql查询字段类型为json时的两种查询方式

    表结构如下: id varchar(32) info json 数据: id = 1 info = {"age": "18","disname":"小明"} -------------------------------------------- 现在我需要获取info中disanme的值,查询方法有: 1. select t.id,JSON_EXTRACT(t.info,'$.disname') as disname fro

  • MySQL查询性能优化七种方式索引潜水

    目录 前言: 有读者可能会一脸懵? 啥是索引潜水? 你给起的名字的吗?有没有索引蛙泳? 这个名字还真不是我起的,今天要讲的知识点就叫索引潜水(Index dive) . 先要从一件怪事说起: 我先造点数据复现一下问题,创建一张用户表: CREATE TABLE `user` (  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',  `name` varchar(100) NOT NULL DEFAULT '' COM

  • Mysql查询以某"字符串"开头的查询方式

    目录 Mysql查询以某"字符串"开头的查询 查询不以某个或者某些字符串为开头的字符串 查询以某个或者某些字符串为开头的字符串 Mysql查询条件字符串类型 = 0 假如有表A A表中有以下数据 Mysql查询以某"字符串"开头的查询 查询不以某个或者某些字符串为开头的字符串 1.使用left()函数 select * from order where left(id,2)<>"AB"; 2.使用like select * from

  • MySQL 查询 并集、交集、差集方式

    目录 MySQL查询交集.并集.差集 背景和使用的数据样本 基本语法 注意事项 总结 MySQL查询交集.并集.差集 背景和使用的数据样本 该章节学些主要涉及到Datawhale SQL 组队学习任务: 本次使用的数据,由Datawhale 开源提供,具体代码见文章尾部:各位看官可以直接复制到MySQL Workbench 上运行生成数据库和表格. MySQL WorkBench 如何对数据进行我们常见的集合运算呢? Union. INTERSECT(遗憾的是MySQL 8.0 不支持该运算用w

  • mysql查询语句中用户变量的使用代码解析

    上一篇文章中我们介绍了MySQL优化总结-查询总条数.这篇文章我们来介绍下查询语句中的另一个知识:用户变量的使用代码解析. 先上代码吧 SELECT `notice`.`id` , `notice`.`fid` , `notice`.`has_read` , `notice`.`notice_time` , `notice`.`read_time` , `f`.`fnum` , `f`.`forg` , `f`.`fdst` , `f`.`actual_parking` AS `parking`

  • MySQL 语句注释方式简介

    MySQL支持三种注释方式: 1.从'#'字符从行尾. 2.从'-- '序列到行尾.请注意'-- '(双破折号)注释风格要求第2个破折号后面至少跟一个空格符(例如空格.tab.换行符等等). 3.从/*序列到后面的*/序列.结束序列不一定在同一行中,因此该语法允许注释跨越多行. 下面的例子显示了3种风格的注释: //在mysql中如何写注释语句 mysql> SELECT 1+1; # 这个注释直到该行结束 mysql> SELECT 1+1; -- 这个注释直到该行结束 mysql>

  • 如何设计高效合理的MySQL查询语句

    MySQL查询语句大家都在用,但是应该如何设计高效合理的MySQL查询语句呢?下面就教您MySQL查询语句的合理设计方法,分享给大家学习学习. 1.合理使用索引 索引是数据库中重要的数据结构,它的根本目的就是为了提高查询效率.现在大多数的数据库产品都采用IBM最先提出的ISAM索引结构.索引的使用要恰到好处,其使用原则如下: ●在经常进行连接,但是没有指定为外键的列上建立索引,而不经常连接的字段则由优化器自动生成索引. ●在频繁进行排序或分组(即进行group by或order by操作)的列上

  • MySql查询时间段的方法

    本文实例讲述了MySql查询时间段的方法.分享给大家供大家参考.具体方法如下: MySql查询时间段的方法未必人人都会,下面为您介绍两种MySql查询时间段的方法,供大家参考. MySql的时间字段有date.time.datetime.timestamp等,往往我们在存储数据的时候将整个时间存在一个字段中,采用datetime类型:也可能采用将日期和时间分离,即一个字段存储date,一个字段存储时间time.无论怎么存储,在实际应用中,很可能会出现包含"时间段"类型的查询,比如一个访

  • MySQL查询结果复制到新表的方法(更新、插入)

    MySQL中可以将查询结果复制到另外的一张表中,复制的话通常有两种情况,一种是更新已有的数据,另一种是插入一条新记录.下面通过例子来说明.首先构建两个测试表. 表t1: 表t2: 1.如果t2表中存在score值,将score更新到t1表中.方法如下: UPDATE t1,t2 SET t1.score = t2.score WHERE t1.id = t2.id AND t2.score IS NOT NULL 这就是将查询结果作为条件更新另一张表,当然,t2也可以是更为复杂的一个查询结果而不

随机推荐