MYSQL递归查询使用总结

1 篇文章 0 订阅
0 篇文章 0 订阅

在做菜单权限分配时用到的SQL递归查询,总结一下:

SELECT 
  * 
FROM
  treenodes 
WHERE id IN 
  (SELECT 
    id 
  FROM
    treenodes 
  WHERE pid = 1 
  UNION
  (SELECT 
    * 
  FROM
    (SELECT 
      id,
      nodename,
      pid,
      (@pv := CONCAT(@pv, ',', id)) AS a 
    FROM
      treenodes 
    ORDER BY pid,
      id) depart_sorted,
    (SELECT 
      @pv := 1) initialisation 
  WHERE FIND_IN_SET(pid, @pv) 
    AND LENGTH(@pv := CONCAT(@pv, ',', id)))) ;

-- --------------------------------------------------------------------------------------------
SELECT 
  id AS ID,
  pid AS 父ID,
  levels AS 父到子之间级数,
  paths AS 父到子路径 
FROM
  (SELECT 
    id,
    pid,
    @le := IF (
      pid = 0,
      0,
      IF(
        LOCATE(CONCAT('|', pid, ':'), @pathlevel) > 0,
        -- @pathlevel中是否存在 |pid
        SUBSTRING_INDEX(
          SUBSTRING_INDEX(@pathlevel, CONCAT('|', pid, ':'), - 1),
          '|',
          1
        ) + 1 -- 存在则
        ,
        @le + 1
      )
    ) levels,
    @pathlevel := CONCAT(@pathlevel, '|', id, ':', @le, '|') pathlevel,
    @pathnodes := IF(
      pid = 0,
      ',0',
      CONCAT_WS(
        ',',
        IF(
          LOCATE(CONCAT('|', pid, ':'), @pathall) > 0,
          SUBSTRING_INDEX(
            SUBSTRING_INDEX(@pathall, CONCAT('|', pid, ':'), - 1),
            '|',
            1
          ),
          @pathnodes
        ),
        pid
      )
    ) paths,
    @pathall := CONCAT(@pathall, '|', id, ':', @pathnodes, '|') pathall 
  FROM
    treenodes,
    (SELECT 
      @le := 0,
      @pathlevel := '',
      @pathall := '',
      @pathnodes := '') vv 
  ORDER BY pid,
    id) src 
ORDER BY id ;

-- -----------------------------------------------------------------------查询父节点(非递归)
SELECT 
  id,
  nodename,
  pid 
FROM
  (SELECT 
    @r AS _id,
    (SELECT 
      @r := pid 
    FROM
      treenodes 
    WHERE id = _id) AS parent_id,
    @l := @l + 1 AS lvl 
  FROM
    (SELECT 
      @r := 4,
      @l := 0) vars,
    treenodes h 
  WHERE @r <> 0) T1 
  JOIN treenodes T2 
    ON T1._id = T2.id 
ORDER BY id ;

-- -----------------------------------------------------------------------------查询父节点(递归)
DELIMITER $$

CREATE FUNCTION queryParents (nodeId INT) RETURNS VARCHAR (4000) DETERMINISTIC 
BEGIN
  DECLARE sTemp VARCHAR (4000) ;
  DECLARE sTempChd VARCHAR (4000) ;
  SET sTemp = '$' ;
  SET sTempChd = CAST(nodeId AS CHAR) ;
  SET sTemp = CONCAT(sTemp, ',', sTempChd) ;
  SELECT 
    pid INTO sTempChd 
  FROM
    treenodes 
  WHERE id = sTempChd ;
  WHILE
    sTempChd <> 0 DO SET sTemp = CONCAT(sTemp, ',', sTempChd) ;
    SELECT 
      pid INTO sTempChd 
    FROM
      treenodes 
    WHERE id = sTempChd ;
  END WHILE ;
  RETURN sTemp ;
END $$

DELIMITER ;

SELECT 
  queryParents (11) ;

SELECT 
  * 
FROM
  treenodes 
WHERE FIND_IN_SET(id, queryParents (11)) ;

-- ------------------------------------------------------------查询子节点
WITH RECURSIVE TEMP AS 
(SELECT 
  id,
  nodename,
  pid 
FROM
  `treenodes` 
WHERE id = 1 
UNION
ALL 
SELECT 
  B.id,
  B.nodename,
  B.pid 
FROM
  TEMP A 
  INNER JOIN `treenodes` B 
    ON B.pid = A.Id) 
SELECT 
  Id,
  nodename,
  pid 
FROM
  TEMP -- ------------------------------- ------------------------------------------------------
  DELIMITER $$

CREATE FUNCTION getChildren (nodeId INT) RETURNS VARCHAR (4000) DETERMINISTIC 
BEGIN
  DECLARE oTemp VARCHAR (4000) ;
  DECLARE oTempChild VARCHAR (4000) ;
  SET oTemp = '' ;
  SET oTempChild = CAST(nodeId AS CHAR) ;
  WHILE
    oTempChild IS NOT NULL DO SET oTemp = CONCAT(oTemp, ',', oTempChild) ;
    SELECT 
      GROUP_CONCAT(id) INTO oTempChild 
    FROM
      treenodes 
    WHERE FIND_IN_SET(pid, oTempChild) > 0 ;
  END WHILE ;
  RETURN oTemp ;
END $$

DELIMITER ;

SELECT 
  getChildren (1) ;

SELECT 
  * 
FROM
  treenodes 
WHERE FIND_IN_SET(id, getChildren (1)) ;

SELECT 
  * 
FROM
  treenodes 
WHERE id IN 
  (SELECT 
    id 
  FROM
    getChildren (1)) ;

DELETE 
FROM
  (SELECT 
    id 
  FROM
    treenodes 
  WHERE FIND_IN_SET(id, getChildren (1))) ;

SELECT 
  FIND_IN_SET(id, getChildren (1)) 
FROM
  treenodes ;

-- 删除节点以及对应的子节点
DELETE 
  treenodes 
FROM
  (SELECT 
    id 
  FROM
    treenodes 
  WHERE FIND_IN_SET(id, getChildren (1))) AS deleting,
  treenodes 
WHERE deleting.id = treenodes.id -- --------------------------------------------------------------------------
  -- 查询节点以及对应的子节点
  SELECT 
    * 
  FROM
    (SELECT 
      id 
    FROM
      treenodes 
    WHERE FIND_IN_SET(id, getChildren (1))) AS deleting,
    treenodes 
  WHERE deleting.id = treenodes.id -- 数据
    INSERT INTO `treenodes` 
    VALUES
      ('1', 'A', '0') ;

INSERT INTO `treenodes` 
VALUES
  ('2', 'B', '1') ;

INSERT INTO `treenodes` 
VALUES
  ('3', 'C', '1') ;

INSERT INTO `treenodes` 
VALUES
  ('4', 'D', '2') ;

INSERT INTO `treenodes` 
VALUES
  ('5', 'E', '2') ;

INSERT INTO `treenodes` 
VALUES
  ('6', 'F', '3') ;

INSERT INTO `treenodes` 
VALUES
  ('7', 'G', '6') ;

INSERT INTO `treenodes` 
VALUES
  ('8', 'H', '0') ;

INSERT INTO `treenodes` 
VALUES
  ('9', 'I', '8') ;

INSERT INTO `treenodes` 
VALUES
  ('10', 'J', '8') ;

INSERT INTO `treenodes` 
VALUES
  ('11', 'K', '8') ;

INSERT INTO `treenodes` 
VALUES
  ('12', 'L', '9') ;

INSERT INTO `treenodes` 
VALUES
  ('13', 'M', '9') ;

INSERT INTO `treenodes` 
VALUES
  ('14', 'N', '12') ;

INSERT INTO `treenodes` 
VALUES
  ('15', 'O', '12') ;

INSERT INTO `treenodes` 
VALUES
  ('16', 'P', '15') ;

INSERT INTO `treenodes` 
VALUES
  ('17', 'Q', '15') ;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值