zoukankan      html  css  js  c++  java
  • 数据库树形结构查询

    数据库树形结构查询

    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));

     

  • 相关阅读:
    图形与文本
    Cookie处理函数练习
    jspSmartUpload上传下载全攻略
    SmartUpload 上传图片
    无下拉菜单
    servlet中使用SmartUpload组件实现上传
    乱码
    DIV+CSS 要兼容 IE8.0 应注意些什么?
    虚拟目录中的web.config不被上级目录的web.config影响的处理
    ASP.NET抓取页面源代码
  • 原文地址:https://www.cnblogs.com/kexinxin/p/11749825.html
Copyright © 2011-2022 走看看