数据库树形结构,正反遍历
?
--从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没有提供类似函数,只能通过在程序或存储过程中利用递归的方式进行实现
定义菜单类
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