Der er ingen måde at gøre dette på i en enkelt forespørgsel. Selv hvis der var, ville det sandsynligvis være meget ineffektivt.
Vi kan gøre det med en lagret procedure og en loop. Med de indekser, du tilføjede, burde det også være ret hurtigt. Dette bruger to tabeller, der vælger noderne fra inputtabellen (A) og indsætter noden og deres børn i (B). Den bytter derefter B med A og gentager, indtil der ikke findes flere ikke-bladsknuder i A. Det gode er, at loop-iterationer kun vil være lige så mange, som deres niveauer mellem inputknuden og den sidste bladknude, hvilket i de fleste tilfælde er nok ikke så dybt. Denne lagrede procedure ville være hurtigere end at gøre den eksternt i kode.
FYI Jeg havde problemer med min installation med at håndtere midlertidige tabeller, hvis du får en 'fejl 2', så fjern det midlertidige søgeord.
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);
Jeg brugte følgende prøvesæt til test:
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);