在列表模型中查找深度

sha*_*nuo 3 mysql sql

我的生产数据看起来类似于此处解释的邻接列表模型...

http://mysql.stu.edu.tw/tech-resources/articles/hierarchical-data.html

我的问题是如何知道嵌套有多深?在这种情况下,从最后一个叶子"Flash"到第一个节点"Electronics"是4.是否有返回此最大深度数的查询?

dan*_*era 6

MYSQL没有CTE也没有递归功能.你可以用'经典循环'来解决它:

DELIMITER $$
DROP FUNCTION IF EXISTS figure_up_depth $$

--encapsulated as a function:
CREATE FUNCTION figure_up_depth(idToSearch INT) RETURNS INT BEGIN

 --var to count steps from node to root:
 DECLARE depth INT;
 SET depth = 1;

 --while we are not on root node:
 WHILE ( idToSearch  is not  null) DO

   SET idToSearch = ( select parent
     from category
     where category_id = idToSearch
                  );

   SET depth = depth + 1;

 END WHILE;

 RETURN depth;

END;
$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

检查:

mysql> select figure_up_depth(7);
+--------------------+
| figure_up_depth(7) |
+--------------------+
|                  4 |
+--------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

2015年7月8日编辑

我意识到OP要求最大深度,而不是节点深度.一个简单的:

mysql> select max( figure_up_depth(category_id) ) as max_depth
       from category;
Run Code Online (Sandbox Code Playgroud)

如果性能重要,正确的解决方案是:

  1. 全部categories.parent放在临时表中table1.
  2. 使用类别连接table1 categories.id = table1.id,将结果连接字段categories.parent放在临时表上table2.
  3. 删除table1并重命名table2table1.
  4. 如果table1有行,请转到步骤2 .

循环次数迭代将是树深度:

DELIMITER $$
DROP PROCEDURE IF EXISTS letsgo;
CREATE PROCEDURE letsgo() BEGIN
 DECLARE R int;
 DECLARE D int;
 SET D=0;
 DROP TEMPORARY TABLE IF EXISTS children;
 CREATE TEMPORARY TABLE children AS (SELECT category_id as id 
                                       FROM category 
                                      WHERE parent is NULL );
 DROP TEMPORARY TABLE IF EXISTS children_prev;
 CREATE TEMPORARY TABLE children_prev AS (SELECT * FROM children );
 SET R = ( SELECT count(*) FROM children ); 
 WHILE ( R > 0 ) DO
   DROP TEMPORARY TABLE IF EXISTS children_aux;
   CREATE TEMPORARY TABLE children_aux AS (
     SELECT category_id as id 
       FROM category R  
       INNER JOIN  children_prev C on C.id = R.parent
   );
   SET R = ( SELECT count(*) FROM children_aux );  
   INSERT INTO children 
      SELECT * FROM children_aux;
   TRUNCATE TABLE children_prev;
   INSERT INTO children_prev
      SELECT * FROM children_aux;   
   SET D=D+1;
 END WHILE;
 SELECT D;
END;
$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

测试:

mysql> call letsgo();
+------+
| D    |
+------+
|    4 |
+------+
1 row in set (0.14 sec)
Run Code Online (Sandbox Code Playgroud)

注意:抱歉脏解决方案,这是mysql:没有CTE,没有递归,没有选择函数递归,没有DO-While,...