mysql-向上-向下-遞歸查詢sql

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

select id from (

              select t1.id,

              if(find_in_set(parent_id, @pids) > 0@pids := concat(@pids',', id), 0) as ischild

              from (

                   select id,parent_id from re_menu t where t.status = 1 order by parent_id, id

                  ) t1,

                  (select @pids := 要查詢的菜單節點 id) t2

             ) t3 where ischild != 0

 比如,要查詢菜單節點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 
--------------------------- 
 Home       0 
 About      
 Contact    
 Legal      
 Privacy    
 Products   
 Support    
我要的要求是根據一個分類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’

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章