Home >Database >Mysql Tutorial >MySQL method to implement tree-like query of all child nodes_MySQL

MySQL method to implement tree-like query of all child nodes_MySQL

WBOY
WBOYOriginal
2016-07-06 13:32:511383browse

The example in this article describes how MySQL implements query of all sub-nodes in a tree. Share it with everyone for your reference, the details are as follows:

In Oracle, we know that there is a Hierarchical Queries. Through CONNECT BY, we can easily query all child nodes under the current node. Unfortunately, there is no corresponding function in the current version of MySQL.

If it is a limited level in MySQL, for example, if we can determine in advance that the maximum depth of the tree is 4, then the depth of the tree with all nodes as roots will not exceed 4, then we can directly implement it through left join .

But many times we cannot control the depth of the tree. At this time, you need to use a stored procedure in MySQL to implement this recursion or implement this recursion in your program. This article discusses several implementation methods.

Sample data:

mysql> create table treeNodes
  -> (
  -> id int primary key,
  -> nodename varchar(20),
  -> pid int
  -> );
Query OK, 0 rows affected (0.09 sec)
mysql> select * from treenodes;
+----+----------+------+
| id | nodename | pid |
+----+----------+------+
| 1 | A    |  0 |
| 2 | B    |  1 |
| 3 | C    |  1 |
| 4 | D    |  2 |
| 5 | E    |  2 |
| 6 | F    |  3 |
| 7 | G    |  6 |
| 8 | H    |  0 |
| 9 | I    |  8 |
| 10 | J    |  8 |
| 11 | K    |  8 |
| 12 | L    |  9 |
| 13 | M    |  9 |
| 14 | N    |  12 |
| 15 | O    |  12 |
| 16 | P    |  15 |
| 17 | Q    |  15 |
+----+----------+------+
17 rows in set (0.00 sec)

The tree diagram is as follows

 1:A
 +-- 2:B
 |  +-- 4:D
 |  +-- 5:E
 +-- 3:C
    +-- 6:F
      +-- 7:G
 8:H
 +-- 9:I
 |  +-- 12:L
 |  |  +--14:N
 |  |  +--15:O
 |  |    +--16:P
 |  |    +--17:Q
 |  +-- 13:M
 +-- 10:J
 +-- 11:K

Method 1: Use the function to get all child node numbers.

Create a function getChildLst to get a string consisting of all child node numbers.

mysql> delimiter //
mysql>
mysql> CREATE FUNCTION `getChildLst`(rootId INT)
  -> RETURNS varchar(1000)
  -> BEGIN
  ->  DECLARE sTemp VARCHAR(1000);
  ->  DECLARE sTempChd VARCHAR(1000);
  ->
  ->  SET sTemp = '$';
  ->  SET sTempChd =cast(rootId as CHAR);
  ->
  ->  WHILE sTempChd is not null DO
  ->   SET sTemp = concat(sTemp,',',sTempChd);
  ->   SELECT group_concat(id) INTO sTempChd FROM treeNodes where FIND_IN_SET(pid,sTempChd)>0;
  ->  END WHILE;
  ->  RETURN sTemp;
  -> END
  -> //
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> delimiter ;

Use us to use the find_in_set function directly with this getChildlst to find

mysql> select getChildLst(1);
+-----------------+
| getChildLst(1) |
+-----------------+
| $,1,2,3,4,5,6,7 |
+-----------------+
1 row in set (0.00 sec)
mysql> select * from treeNodes
  -> where FIND_IN_SET(id, getChildLst(1));
+----+----------+------+
| id | nodename | pid |
+----+----------+------+
| 1 | A    |  0 |
| 2 | B    |  1 |
| 3 | C    |  1 |
| 4 | D    |  2 |
| 5 | E    |  2 |
| 6 | F    |  3 |
| 7 | G    |  6 |
+----+----------+------+
7 rows in set (0.01 sec)
mysql> select * from treeNodes
  -> where FIND_IN_SET(id, getChildLst(3));
+----+----------+------+
| id | nodename | pid |
+----+----------+------+
| 3 | C    |  1 |
| 6 | F    |  3 |
| 7 | G    |  6 |
+----+----------+------+
3 rows in set (0.01 sec)

Advantages: Simple, convenient, no limit on the depth of the recursive call level (max_sp_recursion_depth, maximum 255);

Disadvantages: The length is limited. Although RETURNS varchar(1000) can be expanded, there is always a maximum limit.

The current version of MySQL (5.1.33-community) does not support recursive calls of functions.

Method 2: Using temporary tables and procedural recursion

Create the stored procedure as follows. createChildLst is a recursive process, and showChildLst is a calling entry process to prepare and initialize temporary tables.

mysql> delimiter //
mysql>
mysql> # 入口过程
mysql> CREATE PROCEDURE showChildLst (IN rootId INT)
  -> BEGIN
  -> CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst
  ->  (sno int primary key auto_increment,id int,depth int);
  -> DELETE FROM tmpLst;
  ->
  -> CALL createChildLst(rootId,0);
  ->
  -> select tmpLst.*,treeNodes.* from tmpLst,treeNodes where tmpLst.id=treeNodes.id order by tmpLst.sno;
  -> END;
  -> //
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> # 递归过程
mysql> CREATE PROCEDURE createChildLst (IN rootId INT,IN nDepth INT)
  -> BEGIN
  -> DECLARE done INT DEFAULT 0;
  -> DECLARE b INT;
  -> DECLARE cur1 CURSOR FOR SELECT id FROM treeNodes where pid=rootId;
  -> DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  ->
  -> insert into tmpLst values (null,rootId,nDepth);
  ->
  -> OPEN cur1;
  ->
  -> FETCH cur1 INTO b;
  -> WHILE done=0 DO
  ->     CALL createChildLst(b,nDepth+1);
  ->     FETCH cur1 INTO b;
  -> END WHILE;
  ->
  -> CLOSE cur1;
  -> END;
  -> //
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;

Pass in the node when calling

mysql> call showChildLst(1);
+-----+------+-------+----+----------+------+
| sno | id  | depth | id | nodename | pid |
+-----+------+-------+----+----------+------+
|  4 |  1 |   0 | 1 | A    |  0 |
|  5 |  2 |   1 | 2 | B    |  1 |
|  6 |  4 |   2 | 4 | D    |  2 |
|  7 |  5 |   2 | 5 | E    |  2 |
|  8 |  3 |   1 | 3 | C    |  1 |
|  9 |  6 |   2 | 6 | F    |  3 |
| 10 |  7 |   3 | 7 | G    |  6 |
+-----+------+-------+----+----------+------+
7 rows in set (0.13 sec)
Query OK, 0 rows affected, 1 warning (0.14 sec)
mysql>
mysql> call showChildLst(3);
+-----+------+-------+----+----------+------+
| sno | id  | depth | id | nodename | pid |
+-----+------+-------+----+----------+------+
|  1 |  3 |   0 | 3 | C    |  1 |
|  2 |  6 |   1 | 6 | F    |  3 |
|  3 |  7 |   2 | 7 | G    |  6 |
+-----+------+-------+----+----------+------+
3 rows in set (0.11 sec)
Query OK, 0 rows affected, 1 warning (0.11 sec)

Depth is the depth, so that the program can perform some display formatting. Similar to the level pseudo column in Oracle. sno is for sorting control only. In this way, you can also perform join queries with other tables in the database through the temporary table tmpLst.

In MySQL, you can use the system parameter max_sp_recursion_depth to control the upper limit of the number of levels of recursive calls. In the following example, set it to 12.

mysql> set max_sp_recursion_depth=12;
Query OK, 0 rows affected (0.00 sec)

Advantages: More flexible processing and layer display. And the results can be obtained in the order of tree traversal.

Disadvantages: Recursion has a limit of 255.

Method 3: Use intermediate tables and procedures

(This method is adapted from the sample provided by yongyupost2000)
Create the stored procedure as follows. Since MySQL does not allow multiple references to a temporary table in the same statement, this can only be achieved by using the ordinary table tmpLst. Of course, your program is responsible for clearing this table after use.

delimiter //
drop PROCEDURE IF EXISTS showTreeNodes_yongyupost2000//
CREATE PROCEDURE showTreeNodes_yongyupost2000 (IN rootid INT)
BEGIN
 DECLARE Level int ;
 drop TABLE IF EXISTS tmpLst;
 CREATE TABLE tmpLst (
 id int,
 nLevel int,
 sCort varchar(8000)
 );
 Set Level=0 ;
 INSERT into tmpLst SELECT id,Level,ID FROM treeNodes WHERE PID=rootid;
 WHILE ROW_COUNT()>0 DO
 SET Level=Level+1 ;
 INSERT into tmpLst
  SELECT A.ID,Level,concat(B.sCort,A.ID) FROM treeNodes A,tmpLst B
  WHERE A.PID=B.ID AND B.nLevel=Level-1 ;
 END WHILE;
END;
//
delimiter ;
CALL showTreeNodes_yongyupost2000(0);

After execution, a tmpLst table will be generated, nLevel is the node depth, and sCort is the sorting field.

How to use

SELECT concat(SPACE(B.nLevel*2),'+--',A.nodename)
FROM treeNodes A,tmpLst B
WHERE A.ID=B.ID
ORDER BY B.sCort;
+--------------------------------------------+
| concat(SPACE(B.nLevel*2),'+--',A.nodename) |
+--------------------------------------------+
| +--A                    |
|  +--B                   |
|   +--D                  |
|   +--E                  |
|  +--C                   |
|   +--F                  |
|    +--G                 |
| +--H                    |
|  +--J                   |
|  +--K                   |
|  +--I                   |
|   +--L                  |
|    +--N                 |
|    +--O                 |
|     +--P                |
|     +--Q                |
|   +--M                  |
+--------------------------------------------+
17 rows in set (0.00 sec)

Advantages: display of layer number. And the results can be obtained in the order of tree traversal. There is no recursion limit.

Disadvantages: MySQL has restrictions on temporary tables. Only ordinary tables can be used, and they need to be cleaned up afterwards.

The above are some relatively simple implementation methods using stored procedures in MySQL.

Readers who are interested in more MySQL-related content can check out the special topics on this site: "A Complete Collection of MySQL Log Operation Skills", "A Summary of MySQL Transaction Operation Skills", "A Complete Collection of MySQL Stored Procedure Skills", and "A Summary of MySQL Database Lock Related Skills" 》and《Summary of commonly used functions in MySQL》

I hope this article will be helpful to everyone in MySQL database planning.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn