Няма начин да направите това с една заявка. Дори и да имаше, вероятно би било много неефективно.
Можем да го направим със съхранена процедура и цикъл. С индексите, които добавихте, също трябва да е доста бързо. Това използва две таблици за избор на възлите от входната таблица (A) и вмъкване на възела и техните деца в (B). След това разменя B с A и се повтаря, докато в A не съществуват повече нелистови възли. Хубавото е, че итерациите на цикъл биха били само толкова, колкото са нивата между входния възел и последния листов възел, което в повечето случаи е вероятно не толкова дълбоко. Тази съхранена процедура би била по-бърза, отколкото извършването й външно в код.
За Ваше сведение, имах затруднения с моята инсталация да обработва временни таблици, ако получите „грешка 2“, премахнете временната ключова дума.
delimiter $$
drop procedure if exists GetLeafNodes $$
create procedure GetLeafNodes(nodeid int)
begin
declare N int default 1;
-- create two working sets of IDs, we'll go back and forth between these two sets
drop temporary table if exists A;
drop temporary table if exists B;
create temporary table A(node int, child int);
create temporary table B(node int, child int);
-- insert our single input node into the working set
insert into A values (null, nodeid);
while (N>0) do
-- keep selecting child nodes for each node we are now tracking
-- leaf nodes will end up with the child set to null
insert into B
select ifnull(A.child,A.node), tree.ID
from A
left outer join DATA_TREE as tree on A.child=tree.parent_id;
-- now swap A and B
rename table A to temp, B to A, temp to B;
-- remove non-leaf nodes from table B
delete from B;
-- exit when there are no longer any non-leaf nodes in A
set N=(select count(*) from A where child is not null);
end while;
-- now output our list of leaf nodes
select node from A;
drop temporary table A;
drop temporary table B;
end $$
DELIMITER ;
call GetLeafNodes(4);
Използвах следния набор от примери за тестване:
CREATE TABLE `DATA_TREE` (
`ID` int(11) NOT NULL,
`PARENT_ID` int(11) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `ID_UNIQUE` (`ID`),
KEY `fk_DATA_TREE_1_idx` (`PARENT_ID`)
) ENGINE=InnoDB
;
insert into DATA_TREE values
(1,0),(2,1),(3,1),(4,1),(5,3),(6,3),(7,4),(8,4),(9,4),(10,6),(11,6),(12,7),(13,9),(14,9),(15,12),(16,12),(17,12),(18,14);