mysql和oracle不同沒有相關的遞歸查詢的函數,要麼自己寫相應的函數(存過)要麼寫sql,以下是自己結合一篇博文,以及自己的項目實踐。
前期準備:mysql數據庫,數據字典表:
--表結構--
CREATE TABLE `csc_consult_servicetype` (
`id` bigint(11) NOT NULL COMMENT '主鍵',
`node_id` int(11) NOT NULL COMMENT '節點ID',
`serv_type` int(11) NOT NULL COMMENT '業務類型細類,字典編碼:,servtype',
`node_parent_id` int(11) NOT NULL COMMENT '父親節點ID',
`node_code` varchar(100) NOT NULL COMMENT '節點編碼',
`node_name` varchar(100) NOT NULL COMMENT '節點名稱',
`node_jt_code` varchar(50) DEFAULT NULL COMMENT '節點集團編碼',
`node_jt_name` varchar(100) DEFAULT NULL COMMENT '節點集團名稱',
`node_stop` int(2) NOT NULL COMMENT '是否啓用 ,字典編碼:isorno',
`node_memo` varchar(200) DEFAULT NULL COMMENT '備註',
`node_pinyin` varchar(100) DEFAULT NULL COMMENT '節點拼音',
`node_show` int(2) NOT NULL COMMENT '是否展示,字典編碼:isorno',
`sms_content` varchar(1000) DEFAULT NULL COMMENT '內網短信內容',
`month_bill_send` bigint(20) NOT NULL COMMENT '服務選項',
`gc_code` varchar(4) DEFAULT NULL COMMENT '集團服務指標編碼',
`dff_policy` varchar(4) DEFAULT NULL COMMENT '生效策略',
`dff_date` datetime DEFAULT NULL COMMENT '生效時間',
`order_id` int(11) NOT NULL COMMENT '順序',
`prefix` varchar(10) DEFAULT NULL COMMENT '前綴模板',
`suffix` varchar(10) DEFAULT NULL COMMENT '後綴模板',
`outer_net_code` varchar(500) DEFAULT NULL COMMENT '外網短信模板編碼',
`cst_content` varchar(1000) DEFAULT NULL COMMENT '來電完結原因',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
關鍵點是這四個字段:
其中首層節點的node_id = 0,node_parent_id=-1
1.向下遞歸:
關鍵sql-或者稱爲模板sql:
SELECT NODE_ID FROM(
SELECT t1.NODE_ID,
IF (
find_in_set(NODE_PARENT_ID, @pids) > 0,
@pids := concat(@pids, ',', NODE_ID),
-1
) AS ischild
FROM ( SELECT NODE_ID, NODE_PARENT_ID FROM csc_consult_servicetype t
WHERE
t.NODE_STOP = 0
and t.NODE_SHOW = 0
and t.SERV_TYPE=56
ORDER BY
NODE_PARENT_ID,
NODE_ID
) t1,
(
SELECT
@pids := 15
) t2
) t3
WHERE
ischild != -1
說明:
-- 某個節點的數據
SELECT SERV_TYPE,NODE_ID,NODE_PARENT_ID,NODE_CODE,NODE_NAME,NODE_JT_CODE,order_id from csc_consult_servicetype a
where a.NODE_STOP = 0 and a.NODE_SHOW = 0 and NODE_ID =15 and SERV_TYPE= 56 ORDER BY order_id;
查詢該節點下的全部葉子節點
--查詢向下的節點--
SELECT SERV_TYPE,NODE_ID,NODE_PARENT_ID,NODE_CODE,NODE_NAME,NODE_JT_CODE,order_id from csc_consult_servicetype a
where a.NODE_STOP = 0 and a.NODE_SHOW = 0 and a.SERV_TYPE=56 and
a.NODE_ID in (SELECT NODE_ID FROM(
SELECT t1.NODE_ID,
IF (
find_in_set(NODE_PARENT_ID, @pids) > 0,
@pids := concat(@pids, ',', NODE_ID),
-1
) AS ischild
FROM ( SELECT NODE_ID, NODE_PARENT_ID FROM csc_consult_servicetype t
WHERE
t.NODE_STOP = 0
and t.NODE_SHOW = 0
and t.SERV_TYPE=56
ORDER BY
NODE_PARENT_ID,
NODE_ID
) t1,
(
SELECT
@pids := 15
) t2
) t3
WHERE
ischild != -1);
結果:
2.向上遞歸查到首層的節點爲止:
關鍵sql:
SELECT DISTINCT T2.NODE_ID
FROM (
SELECT DISTINCT
@r AS t1_id,
(SELECT @r:= NODE_PARENT_ID FROM csc_consult_servicetype WHERE
NODE_STOP = 0
and NODE_SHOW = 0
and SERV_TYPE=56
and NODE_ID = t1_id) AS NODE_PARENT_ID
FROM
(SELECT @r:= 125) vars,
csc_consult_servicetype h
WHERE @r <> -1) T1
JOIN csc_consult_servicetype T2
ON T1.t1_id = T2.NODE_ID
入參:@r:= 125 其他說明和向下遞歸類似
實例:
select SERV_TYPE,NODE_ID,NODE_PARENT_ID,NODE_CODE,NODE_NAME,NODE_JT_CODE,order_id
from csc_consult_servicetype
where NODE_STOP = 0 and NODE_SHOW = 0
and SERV_TYPE=56
and NODE_ID = 125;
遞歸sql:
SELECT SERV_TYPE,NODE_ID,NODE_PARENT_ID,NODE_CODE,NODE_NAME,NODE_JT_CODE,order_id from csc_consult_servicetype a
where a.NODE_STOP = 0 and a.NODE_SHOW = 0 and a.SERV_TYPE=56 and
a.NODE_ID in(
SELECT DISTINCT T2.NODE_ID
FROM (
SELECT DISTINCT
@r AS t1_id,
(SELECT @r:= NODE_PARENT_ID FROM csc_consult_servicetype WHERE
NODE_STOP = 0
and NODE_SHOW = 0
and SERV_TYPE=56
and NODE_ID = t1_id) AS NODE_PARENT_ID
FROM
(SELECT @r:= 125) vars,
csc_consult_servicetype h
WHERE @r <> -1) T1
JOIN csc_consult_servicetype T2
ON T1.t1_id = T2.NODE_ID );
如圖 上層的每一個節點都找到。
參考資料:
向下遞歸:
https://www.cnblogs.com/rainydayfmb/p/8028868.html
mysql 遞歸查找菜單節點的所有子節點
背景
項目中遇到一個需求,要求查處菜單節點的所有節點,在網上查了一下,大多數的方法用到了存儲過程,由於線上環境不能隨便添加存儲過程,
因此在這裏採用類似遞歸的方法對菜單的所有子節點進行查詢。
準備
創建menu表:
CREATE TABLE `menu` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '菜單id', `parent_id` int(11) DEFAULT NULL COMMENT '父節點id', `menu_name` varchar(128) DEFAULT NULL COMMENT '菜單名稱', `menu_url` varchar(128) DEFAULT '' COMMENT '菜單路徑', `status` tinyint(3) DEFAULT '1' COMMENT '菜單狀態 1-有效;0-無效', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=12212 DEFAULT CHARSET=utf8;
插入數據:
INSERT INTO `menu` VALUES ('0', null, '菜單0', ' ', '1'); INSERT INTO `menu` VALUES ('1', '0', '菜單1', '', '1'); INSERT INTO `menu` VALUES ('11', '1', '菜單11', '', '1'); INSERT INTO `menu` VALUES ('12', '1', '菜單12', '', '1'); INSERT INTO `menu` VALUES ('13', '1', '菜單13', '', '1'); INSERT INTO `menu` VALUES ('111', '11', '菜單111', '', '1'); INSERT INTO `menu` VALUES ('121', '12', '菜單121', '', '1'); INSERT INTO `menu` VALUES ('122', '12', '菜單122', '', '1'); INSERT INTO `menu` VALUES ('1221', '122', '菜單1221', '', '1'); INSERT INTO `menu` VALUES ('1222', '122', '菜單1222', '', '1'); INSERT INTO `menu` VALUES ('12211', '1222', '菜單12211', '', '1');
得到的目錄結構如下圖所示:
查詢
先貼出sql語句:
1 2 3 4 5 6 7 8 |
|
比如,要查詢菜單節點12的所有子節點,則查處的結果爲:
分析
首先分析from後面的語句,根據parent_id和id 排序,並將要查詢的菜單節點當做變量,from後面的結果爲
接下來看if(express1,express2,express3)條件語句,if語句類似三目運算符,當exprss1成立時,執行express2,否則執行express3;
FIND_IN_SET(str,strlist),str 要查詢的字符串,strlist 字段名 參數以”,”分隔 如 (1,2,6,8),查詢字段(strlist)中包含(str)的結果,返回結果爲null或記錄
如果parent_id 在@pid中,則將@pid 裏面再加上parent_id,按行依次執行,執行過程如下表所示:
這時,顯示的id就是菜單id爲12的所有子節點id
向上遞歸:
http://blog.sina.com.cn/s/blog_8edc37a80101ij6c.html
mysql遞歸查詢,mysql中從子類ID查詢所有父類(做無限分類經常用到)
由於mysql 不支持類似 oracle with ...connect的 遞歸查詢語法
之前一直以爲類似的查詢要麼用存儲過程要麼只能用程序寫遞歸查詢.
現在發現原來一條sql語句也是可以搞定的
先來看數據表的結構如下:
id name parent_id
---------------------------
1 Home 0
2 About 1
3 Contact 1
4 Legal 2
5 Privacy 4
6 Products 1
7 Support 1
我要的要求是根據一個分類ID(這個分類ID可能是一個子分類),得到所有的父分類,下面是相應的SQL:
SELECT T2.id, T2.name
FROM (
SELECT
@r AS _id,
(SELECT @r := parent_id FROM table1 WHERE id = _id) AS parent_id,
@l := @l + 1 AS lvl
FROM
(SELECT @r := 5, @l := 0) vars,
table1 h
WHERE @r <> 0) T1
JOIN table1 T2
ON T1._id = T2.id
ORDER BY T1.lvl DESC
代碼@r := 5標示查詢id爲5的所有父類。結果如下
1, ‘Home’
2, ‘About’
4, ‘Legal’
5, ‘Privacy’