Il n'y a aucun moyen de le faire en une seule requête. Même s'il y en avait, ce serait probablement très inefficace.
Nous pouvons le faire avec une procédure stockée et une boucle. Avec les index que vous avez ajoutés, cela devrait également être assez rapide. Cela utilise deux tables sélectionnant les nœuds de la table d'entrée (A) et insérant le nœud et leurs enfants dans (B). Il échange ensuite B contre A et se répète jusqu'à ce qu'il n'existe plus de nœuds non feuilles dans A. La bonne chose est que les itérations de boucle ne seraient qu'autant qu'il y a de niveaux entre le nœud d'entrée et le dernier nœud feuille, qui dans la plupart des cas est probablement pas si profond. Cette procédure stockée serait plus rapide que de la faire en externe dans le code.
Pour votre information, j'ai eu des difficultés avec mon installation pour gérer les tables temporaires, si vous obtenez une "erreur 2", supprimez le mot-clé temporaire.
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);
J'ai utilisé l'ensemble d'échantillons suivant pour les tests :
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);