數據庫樹形結構查詢

數據庫樹形結構查詢

Oracle實現方式

數據庫樹形結構,正反遍歷html

 

--從Root往樹末梢遞歸java

select level ,identity,pid from table_namenode

start with identity=475數據庫

connect by prior identity = pidjson

 

--從末梢往樹ROOT遞歸api

select level ,identity,pid,yylevel from table_namemybatis

start with identity=542app

connect by prior pid = identityide

 

做用: 函數

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

相關文章
相關標籤/搜索