Er is geen manier om dit in een enkele query te doen. Zelfs als dat zo was, zou het waarschijnlijk erg inefficiënt zijn.
We kunnen het doen met een opgeslagen procedure en een lus. Met de indexen die je hebt toegevoegd, zou het ook behoorlijk snel moeten zijn. Dit gebruikt twee tabellen die de knooppunten selecteren uit de invoertabel (A) en het knooppunt en hun kinderen invoegen in (B). Het verwisselt vervolgens B voor A en herhaalt zich totdat er geen niet-bladknooppunten meer zijn in A. Het leuke is dat lusiteraties slechts zoveel zijn als hun niveaus tussen het invoerknooppunt en het laatste bladknooppunt, wat in de meeste gevallen is waarschijnlijk niet zo diep. Deze opgeslagen procedure zou sneller zijn dan het extern in code te doen.
Ter info:ik had problemen met het afhandelen van tijdelijke tabellen tijdens de installatie. Als je een 'error 2' krijgt, verwijder dan het tijdelijke trefwoord.
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);
Ik heb de volgende sampleset gebruikt om te testen:
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);