儲存過程遞迴樹結構實現(某一節點下所有子節點)三種方式
阿新 • • 發佈:2018-12-18
最近專案中碰到需要寫遞迴,就特意實現了集中實現方式,總結一下~
情景:通過給出的機構id,得到該機構id以及所有的子機構資訊,機構id是UUID;
通過三種方式去實現,親自實現過,可直接用:
第一種:通過多次操作資料庫獲得所有子機構資訊。實現如下:
/** * 遞迴獲取某個機構id下面的所有子機構 * @param comTreeBeanHashSet 節點集合 * @param mechanismId 當前機構ID */ private void findChildMechanisms(Set<ComTreeBean> comTreeBeanHashSet, String mechanismId) { ComTreeBean dep=comTreeDao.findByMechanismId(mechanismId); List<ComTreeBean> comTreeBeans = new ArrayList<ComTreeBean>(); comTreeBeans.add(dep); /** * 加入當前機構 */ comTreeBeanHashSet.addAll(comTreeBeans.stream().collect(Collectors.toList())); /** * 獲取子機構 */ List<ComTreeBean> comTreeBeanPars = comTreeDao.findByParentId(mechanismId); for (ComTreeBean d : comTreeBeanPars) { /** * 遞迴子單位 */ findChildMechanisms(comTreeBeanHashSet, d.getUid()); } }
第二種:不會多次操作資料庫,通過一次查詢,獲取所有機構樹資訊,再從當前機構去遞迴獲取所有子機構資訊
//子節點集合 List<ComTreeBean> childMenu = new ArrayList<ComTreeBean>; /** * 獲取某個父節點下面的所有子節點 * @param menuList * @param id 當前機構id * @return */ public static List<ComTreeBean> treeMenuList(List<ComTreeBean> childMenu, List<ComTreeBean> menuList, String id){ for(ComTreeBean mu: menuList){ //遍歷出父id等於引數的id,add進子節點集合 if(id.equals(mu.getParComUid())){ //遞迴遍歷下一級 treeMenuList(childMenu,menuList,mu.getUid()); childMenu.add(mu); } } return childMenu; }
直接使用能獲取所有子機構資訊,但是不能獲取傳入機構資訊,如果想保留當前傳入id機構,在初始化子節點集合時放入當前機構即可,即為:
//子節點集合
List<ComTreeBean> childMenu = comTreeBeanList.stream().filter(comTreeBean ->
pid.equals(comTreeBean.getUid())).collect(Collectors.toList());
當然,這兩種方式都是機構樹的資料不是很大,考慮到如果其他情況下,比如資料量大,就考慮使用第三種方式,通過建立儲存過程實現,我也將其實現了一遍,表例項就不給出了,具體實現如下,可自己建立表例項實驗:
第三種:儲存過程
首先定義執行遞迴操作的儲存過程,如下
-- 首先定義執行遞迴操作的儲存過程:findChildList
CREATE PROCEDURE findChildList(IN id varchar(100))
BEGIN
DECLARE v_dep varchar(100) DEFAULT -1;
DECLARE done varchar(100) DEFAULT 0;
DECLARE C_dep CURSOR FOR SELECT d.id FROM T_COM_INFO d WHERE d.par_com_uid = id;
DECLARE CONTINUE HANDLER FOR NOT found set done=1;
SET @@max_sp_recursion_depth = 10;
INSERT INTO tmp_Dep VALUES (id);
OPEN C_dep;
FETCH C_dep INTO v_dep;
WHILE (done =0)
DO
CALL findChildList(v_dep);
FETCH C_dep INTO v_dep;
END WHILE;
END
然後定義呼叫遞迴操作的儲存過程,如下
-- 再定義呼叫遞迴操作的儲存過程:findDepList
CREATE PROCEDURE findDepList(IN id varchar(100))
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmp_Dep;
CREATE TEMPORARY TABLE tmp_Dep(depId varchar(100));
DELETE FROM tmp_Dep;
CALL findChildList(id);
SELECT distinct tmp_Dep.depId,T_COM_INFO.com_name FROM tmp_Dep,T_COM_INFO where tmp_Dep.depId = T_COM_INFO.id order by depId;
END
呼叫儲存過程及刪除儲存過程,如下:
call findDepList('45e9b12d-165f6037fad-9c1534b1e8dbb5a0c0ec3f70d24f9627')
drop procedure if exists findChildList
drop procedure if exists findDepList
具體就是這樣,順便給出本人寫測試時,id為int型別的儲存過程,如下
-- 首先定義執行遞迴操作的儲存過程:findChildList
CREATE PROCEDURE findChildList(IN id BIGINT)
BEGIN
DECLARE v_dep integer DEFAULT -1;
DECLARE done integer DEFAULT 0;
DECLARE C_dep CURSOR FOR SELECT d.id FROM treenodes d WHERE d.pid = id;
DECLARE CONTINUE HANDLER FOR NOT found set done=1;
SET @@max_sp_recursion_depth = 10;
INSERT INTO tmp_Dep VALUES (id);
OPEN C_dep;
FETCH C_dep INTO v_dep;
WHILE (done =0)
DO
CALL findChildList(v_dep);
FETCH C_dep INTO v_dep;
END WHILE;
END
-- 再定義呼叫遞迴操作的儲存過程:findDepList
CREATE PROCEDURE findDepList(IN id BIGINT)
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmp_Dep;
CREATE TEMPORARY TABLE tmp_Dep(depId INTEGER);
DELETE FROM tmp_Dep;
CALL findChildList(id);
SELECT distinct tmp_Dep.depId,treenodes.nodename FROM tmp_Dep,treenodes where tmp_Dep.depId = treenodes.id order by depId;
END
drop procedure if exists findChildList
drop procedure if exists findDepList
call findDepList(3)