首页 > 数据库技术 > 详细

数据库树形结构查询

时间:2019-10-28 00:11:44      阅读:126      评论:0      收藏:0      [点我收藏+]

数据库树形结构查询

Oracle实现方式

数据库树形结构,正反遍历

?

--从Root往树末梢递归

select level ,identity,pid from table_name

start with identity=475

connect by prior identity = pid

?

--从末梢往树ROOT递归

select level ,identity,pid,yylevel from?table_name

start with identity=542

connect by prior pid = identity

?

作用:

connect by主要用于父子,祖孙,上下级等层级关系的查询

?

语句:

{ CONNECT BY [ NOCYCLE ] condition [AND condition]... [ START WITH condition ]
| START WITH condition CONNECT BY [ NOCYCLE ] condition [AND condition]...}

解释:

start with: 指定起始节点的条件

connect by: 指定父子行的条件关系

prior: 查询父行的限定符,格式: prior column1 = column2 or column1 = prior column2 and ... ,

nocycle: 若数据表中存在循环行,那么不添加此关键字会报错,添加关键字后,便不会报错,但循环的两行只会显示其中的第一条

循环行: 该行只有一个子行,而且子行又是该行的祖先行

connect_by_iscycle: 前置条件:在使用了nocycle之后才能使用此关键字,用于表示是否是循环行,0表示否,1 表示是

connect_by_isleaf: 是否是叶子节点,0表示否,1 表示是

level: level伪列,表示层级,值越小层级越高,level=1为层级最高节点

?

MySQL实现方式

MySQL没有提供类似函数,只能通过在程序或存储过程中利用递归的方式进行实现

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

定义菜单类

public class Menu {

????// 菜单id

????private String id;

????// 菜单名称

????private String name;

????// 父菜单id

????private String parentId;

????// 菜单url

????private String url;

????// 菜单图标

????private String icon;

????// 菜单顺序

????private int order;

????// 子菜单

????private List<Menu> childMenus;

????// ... 省去getter和setter方法以及toString方法

}

?

根据这个类定义数据库,并插入菜单数据

DROP TABLE IF EXISTS `jrbac_menu`;

CREATE TABLE `jrbac_menu` (

`id` varchar(32) NOT NULL COMMENT ‘主键id,uuid32位‘,

`name` varchar(64) NOT NULL COMMENT ‘菜单名称‘,

`parent_id` varchar(32) DEFAULT NULL COMMENT ‘父菜单id‘,

`url` varchar(64) DEFAULT NULL COMMENT ‘访问地址‘,

`icon` varchar(32) DEFAULT NULL COMMENT ‘菜单图标‘,

`order` tinyint(4) DEFAULT ‘0‘ COMMENT ‘菜单顺序‘,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘菜单表‘;

?

-- ----------------------------

-- Records of jrbac_menu

-- ----------------------------

INSERT INTO `jrbac_menu` VALUES (‘1‘, ‘Forms‘, null, ‘forms.html‘, ‘fa fa-edit‘, ‘0‘);

INSERT INTO `jrbac_menu` VALUES (‘2‘, ‘UI Elements‘, null, ‘‘, ‘fa fa-wrench‘, ‘1‘);

INSERT INTO `jrbac_menu` VALUES (‘3‘, ‘Buttons‘, ‘2‘, ‘buttons.html‘, ‘‘, ‘0‘);

INSERT INTO `jrbac_menu` VALUES (‘4‘, ‘Icons‘, ‘2‘, ‘icons.html‘, null, ‘1‘);

INSERT INTO `jrbac_menu` VALUES (‘5‘, ‘Multi-Level Dropdown‘, ‘‘, ‘‘, ‘fa fa-sitemap‘, ‘2‘);

INSERT INTO `jrbac_menu` VALUES (‘6‘, ‘Second Level Item‘, ‘5‘, ‘second.html‘, null, ‘0‘);

INSERT INTO `jrbac_menu` VALUES (‘7‘, ‘Third Level‘, ‘5‘, null, ‘‘, ‘1‘);

INSERT INTO `jrbac_menu` VALUES (‘8‘, ‘Third Level Item‘, ‘7‘, ‘third.html‘, null, ‘0‘);

?

为了演示,我们把可展开的没有做完,仅仅插入几条数据能出效果就可以了。

?

测试方法与递归方法

private final Gson gson = new GsonBuilder().disableHtmlEscaping().create();

@Test

public void testQueryMenuList() {

????// 原始的数据

????List<Menu> rootMenu = menuDao.queryMenuList(null);

?

????// 查看结果

????for (Menu menu : rootMenu) {

????????System.out.println(menu);

????}

????// 最后的结果

????List<Menu> menuList = new ArrayList<Menu>();

????// 先找到所有的一级菜单

????for (int i = 0; i < rootMenu.size(); i++) {

????????// 一级菜单没有parentId

????????if (StringUtils.isBlank(rootMenu.get(i).getParentId())) {

????????????menuList.add(rootMenu.get(i));

????????}

????}

????// 为一级菜单设置子菜单,getChild是递归调用的

????for (Menu menu : menuList) {

????????menu.setChildMenus(getChild(menu.getId(), rootMenu));

????}

????Map<String,Object> jsonMap = new HashMap<>();

????jsonMap.put("menu", menuList);

????System.out.println(gson.toJson(jsonMap));

?

}

?

/**

* 递归查找子菜单

*

* @param id

* 当前菜单id

* @param rootMenu

* 要查找的列表

* @return

*/

private List<Menu> getChild(String id, List<Menu> rootMenu) {

????// 子菜单

????List<Menu> childList = new ArrayList<>();

????for (Menu menu : rootMenu) {

????????// 遍历所有节点,将父菜单id与传过来的id比较

????????if (StringUtils.isNotBlank(menu.getParentId())) {

????????????if (menu.getParentId().equals(id)) {

????????????????childList.add(menu);

????????????}

????????}

????}

????// 把子菜单的子菜单再循环一遍

????for (Menu menu : childList) {// 没有url子菜单还有子菜单

????????if (StringUtils.isBlank(menu.getUrl())) {

????????????// 递归

????????????menu.setChildMenus(getChild(menu.getId(), rootMenu));

????????}

????} // 递归退出条件

????if (childList.size() == 0) {

????????return null;

????}

????return childList;

}

?

menuDao.queryMenuList(null);查找的结果是一条一条的数据

技术分享图片

?

meuDao

package com.jrbac.dao;

?

import java.util.List;

?

import com.jrbac.entity.LoginUser;

import com.jrbac.entity.Menu;

?

public interface MenuDao {

?

????/**

???? * 查找用户的菜单

???? * @param loginUser

???? * @return

???? */

????public List<Menu> queryMenuList(LoginUser loginUser);

}

?

?

mybatis

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jrbac.dao.MenuDao">

????<select id="queryMenuList" resultType="Menu">

????????SELECT

????????????id,`name`,parent_id,url,icon,`order`

????????FROM

????????????jrbac_menu ORDER BY `order` ASC

????</select>

</mapper>

?

?

利用存储过程

创建表

SET FOREIGN_KEY_CHECKS=0;

?

-- ----------------------------

-- Table structure for t_areainfo

-- ----------------------------

DROP TABLE IF EXISTS `t_areainfo`;

CREATE TABLE `t_areainfo` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`level` int(11) DEFAULT NULL,

`name` varchar(255) DEFAULT NULL,

`parentId` int(11) DEFAULT NULL,

`status` int(11) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8;

?

-- ----------------------------

-- Records of t_areainfo

-- ----------------------------

INSERT INTO `t_areainfo` VALUES (‘1‘, ‘0‘, ‘中国‘, ‘0‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘2‘, ‘0‘, ‘华北区‘, ‘1‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘3‘, ‘0‘, ‘华南区‘, ‘1‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘4‘, ‘0‘, ‘北京‘, ‘2‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘5‘, ‘0‘, ‘海淀区‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘6‘, ‘0‘, ‘丰台区‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘7‘, ‘0‘, ‘朝阳区‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘8‘, ‘0‘, ‘北京XX区1‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘9‘, ‘0‘, ‘北京XX区2‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘10‘, ‘0‘, ‘北京XX区3‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘11‘, ‘0‘, ‘北京XX区4‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘12‘, ‘0‘, ‘北京XX区5‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘13‘, ‘0‘, ‘北京XX区6‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘14‘, ‘0‘, ‘北京XX区7‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘15‘, ‘0‘, ‘北京XX区8‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘16‘, ‘0‘, ‘北京XX区9‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘17‘, ‘0‘, ‘北京XX区10‘, ‘4‘, ‘0‘);

INSERT INTO `t_areainfo` VALUES (‘18‘, ‘0‘, ‘北京XX区11‘, ‘4‘, ‘0‘);

?

?

?

存储过程创建

技术分享图片

?

FIND_IN_SET函数说明

FIND_IN_SET(str,strlist)

str 要查询的字符串
strlist 字段名 参数以","分隔 如 (1,2,6,8)
查询字段(strlist)中包含(str)的结果,返回结果为null或记录

?

select * from treenodes where FIND_IN_SET(id, ‘1,2,3,4,5‘);?

使用find_in_set函数一次返回多条记录?

id 是一个表的字段,然后每条记录分别是id等于1,2,3,4,5的时候?

有点类似in (集合)?

select * from treenodes where id in (1,2,3,4,5);

?

?

调用方式

select queryChildrenAreaInfo(2);

select * from t_areainfo where FIND_IN_SET(id, queryChildrenAreaInfo(2));

?

数据库树形结构查询

原文:https://www.cnblogs.com/kexinxin/p/11749825.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!