2014-10-10 59 views
0

對不起,我看到很多關於此的問題,但我不明白更簡單的方法來做到這一點。Mysql遞歸計數和選擇

我: ID | parentId的|名

  • 我怎麼能算一個id的 「兒子」 的數量?
  • 我怎樣才能做一個選擇,返回每個兒子的id和它的「樹層」。
+0

第一個是很容易的......第二變得複雜在MySQL中。你知道最深的水平嗎? – 2014-10-10 23:46:50

+0

第一個..我說「兒子數量」。但我的意思是......整棵樹(兒子 - >孫子 - >等等)。我認爲最深的水平不會超過1000. – 2014-10-10 23:50:30

+1

http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/ – 2014-10-10 23:51:13

回答

1

編輯:起初我有NULL我最頂層節點parent_id。那是不正確的。它應該是零這個工作(據我所知)。我張貼包括NULL我原來的插入語句但我在工作,我不得不更新這些數值爲0。我糾正我下面的測試數據....

與此:http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/

我這樣做。 ..有點你要去的。

mysql> describe table_name; 
+-----------+-------------+------+-----+---------+-------+ 
| Field  | Type  | Null | Key | Default | Extra | 
+-----------+-------------+------+-----+---------+-------+ 
| id  | int(11)  | YES |  | NULL |  | 
| parent_id | int(11)  | YES |  | NULL |  | 
| name  | varchar(20) | YES |  | NULL |  | 
+-----------+-------------+------+-----+---------+-------+ 

insert into table_name values (1, 0, 'one'); -- was parent_id null, was wrong, now zer 
insert into table_name values (2, 1, 'one one'); 
insert into table_name values (3, 2, 'one one one'); 
insert into table_name values (4, 2, 'one one two'); 
insert into table_name values (5, 2, 'one one three'); 
insert into table_name values (6, 5, 'one one three one'); 
insert into table_name values (7, 1, 'one two'); 
insert into table_name values (8, 0, 'two'); -- was parent_id null, was wrong, now zero 
insert into table_name values (9, 8, 'two one'); 

delimiter // 

CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value INT) RETURNS INT 
NOT DETERMINISTIC 
READS SQL DATA 
BEGIN 
     DECLARE _id INT; 
     DECLARE _parent INT; 
     DECLARE _next INT; 
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL; 

     SET _parent = @id; 
     SET _id = -1; 

     IF @id IS NULL THEN 
       RETURN NULL; 
     END IF; 

     LOOP 
       SELECT MIN(id) 
       INTO @id 
       FROM table_name 
       WHERE parent_id = _parent 
         AND id > _id; 
       IF @id IS NOT NULL OR _parent = @start_with THEN 
         SET @level = @level + 1; 
         RETURN @id; 
       END IF; 
       SET @level := @level - 1; 
       SELECT id, parent_id 
       INTO _id, _parent 
       FROM table_name 
       WHERE id = _parent; 
     END LOOP;  
END 
// 
delimiter ; 


SELECT CONCAT(REPEAT(' ', level - 1), CAST(hi.id AS CHAR)) AS treeitem, 
     parent_id, level, name 
FROM (
     SELECT hierarchy_connect_by_parent_eq_prior_id(id) AS id, @level AS level 
     FROM (
       SELECT @start_with := 0, 
         @id := @start_with, 
         @level := 0 
       ) vars, table_name 
     WHERE @id IS NOT NULL 
     ) ho 
JOIN table_name hi 
ON  hi.id = ho.id; 


+---------------+-----------+-------+-------------------+ 
| treeitem  | parent_id | level | name    | 
+---------------+-----------+-------+-------------------+ 
| 1    |   0 |  1 | one    | 
|  2   |   1 |  2 | one one   | 
|   3  |   2 |  3 | one one one  | 
|   4  |   2 |  3 | one one two  | 
|   5  |   2 |  3 | one one three  | 
|    6 |   5 |  4 | one one three one | 
|  7   |   1 |  2 | one two   | 
| 8    |   0 |  1 | two    | 
|  9   |   8 |  2 | two one   | 
+---------------+-----------+-------+-------------------+ 

ķ...如果你想從所有那些亂七八糟的後代的個性化......你需要做的:

select count(*) 
from (select hierarchy_connect_by_parent_eq_prior_id(id) as id, @level as level 
     from (
       select @start_with := 8, --> ID of top node you want to count under 
         @id := @start_with, 
         @level := 0 
       ) vars, table_name 
     where @id is not null 
     ) as x 
where id is not null --> exclude that top node from the count