2013-10-06 2 views
0

Представьте себе у меня есть таблица (Mysql MyISAM) с детьми-родительскими отношениями> (категорией и нескольких уровней подкатегорий)узнать список перевернутой иерархии в MySQL

+--------+---------+ 
| id  |parent_id| 
+--------+---------+ 
| 1  | null | 
| 2  | 1 | 
| 3  | 2 | 
| 4  | 7 | 
| 5  | 1 | 
| 6  | 5 | 
+--------+---------+ 

Как бы вы найти все ребенок некоторых Идентификатор, например запрос на идентификатор 1, будет выводиться: 2,5,3,6? (порядок не имеет значения)

Итак, как сделать обратный поиск детей на этой родительской ссылке?

На данный момент, я цикл в PHP и запроса для parent_id, а затем снова и сцепить все результаты в виде строки, а есть результаты, но это так медленно ...

+0

Почему результаты 4,1,5,6, а не 4,1,3,2,4,1,3, .... Мне кажется, что 1 подключен к 5 и 3 , нет? – Gidil

+0

Смотрите это http://stackoverflow.com/questions/12796113/mysql-how-to-find-leaves-in-specific-node/12797585#12797585 – AgRizzo

+1

@Gidil, извините, только некоторые случайные данные, вы правы, исправлены это –

ответ

0
create table my_table(
id int, 
parent_id int 
); 

insert into my_table values 
(1,null), 
(2,1), 
(3,2), 
(4,7), 
(5,1), 
(6,5); 

Эта хранимая процедура поможет вам всех детей любого данного идентификатора

DELIMITER $$ 
DROP PROCEDURE IF EXISTS get_children$$ 

CREATE PROCEDURE get_children(IN V_KEY INT) 
proc: 
BEGIN 
    DECLARE vid text; 
declare oid text; 
    DECLARE count int; 
    CREATE TEMPORARY TABLE temp_child_nodes(
     id int 
    ); 

    SET vid = V_KEY; 
    INSERT INTO temp_child_nodes(id) SELECT id from my_table where parent_id = vid; 
    SELECT GROUP_CONCAT(concat("'",id,"'")) INTO oid from my_table where parent_id = vid; 

    SET vid = oid; 
    SET count = 0; 
    SET @val = ''; 
    WHILE (vid is NOT NULL) DO 

     SET @sql = CONCAT("INSERT INTO temp_child_nodes(id) SELECT id from my_table where parent_id IN (",vid,")"); 
     PREPARE stmt1 FROM @sql; 
     EXECUTE stmt1; 
     DEALLOCATE PREPARE stmt1; 

     SET @tsql = CONCAT("SELECT GROUP_CONCAT(id) INTO @val from my_table where parent_id IN (", vid, ")"); 
     PREPARE stmt2 FROM @tsql; 
     EXECUTE stmt2; 
     DEALLOCATE PREPARE stmt2; 
     SET vid = @val; 
     SET count = count + 1; 
    END WHILE; 
    #SELECT count; 
    SELECT * from temp_child_nodes; 
    #SELECT oid; 
END 
$$ 

DELIMITER ; 

CALL get_children (1);

mysql> CALL get_children(1); 
+------+ 
| id | 
+------+ 
| 2 | 
| 5 | 
| 3 | 
| 6 | 
+------+ 
4 rows in set (0.22 sec) 

Query OK, 0 rows affected (0.22 sec) 
+0

Im пробуя это прямо сейчас! –

+0

@VincentDuprez: дайте мне знать, если вы столкнулись с любыми проблемами :) – Deepak

+0

Работает! Я пытаюсь изменить его, чтобы получить больше информации в одном вызове (например, в глубину) и добавить дополнительный параметр для установки таблицы, я отправлю его сюда, если у меня получится –

0

Вот sqlfiddle демо по вашему запросу http://sqlfiddle.com/#!2/ca90e/6

если может быть «п» число детей, то вам необходимо использовать хранимую процедуру

+0

спасибо, к сожалению, я получаю неизвестную глубину –

+0

@VincentDuprez: Пожалуйста, обратитесь к моему ответу. Хранимая процедура доставит вам детей любого id до любой глубины – Deepak

1

Итак, благодаря Дипак кода, мне удалось написать это, немного короче читаемым, он принимает таблицу в качестве параметра и возвращает также глубину элемента.

DELIMITER $$ 

CREATE PROCEDURE get_children(IN V_KEY INT,IN SOURCETABLE VARCHAR(255)) 
proc: 
BEGIN 
    DECLARE vid text; 
    DECLARE count int; 

    DROP TABLE IF EXISTS `temp_child_nodes`; 
    CREATE TEMPORARY TABLE temp_child_nodes(id int, depth int); 

    SET vid = V_KEY; 
    SET @val = ''; 
    SET count = 0; 

    WHILE (vid is NOT NULL) DO 

     SET @sql = CONCAT("INSERT INTO temp_child_nodes(id,depth) SELECT id,'",count,"' from ",SOURCETABLE," where parent_id IN (",vid,")"); 
     PREPARE stmt1 FROM @sql; 
     EXECUTE stmt1; 
     DEALLOCATE PREPARE stmt1; 


     SET @tsql = CONCAT("SELECT GROUP_CONCAT(id) INTO @val from ",SOURCETABLE," where parent_id IN (", vid, ")"); 
     PREPARE stmt2 FROM @tsql; 
     EXECUTE stmt2; 
     DEALLOCATE PREPARE stmt2; 
     SET vid = @val; 

     SET count = count + 1; 
    END WHILE; 

    #output data 
    SELECT * from temp_child_nodes; 

END 
$$ 

DELIMITER ; 
Смежные вопросы