Tidak ada cara untuk melakukan ini dalam satu kueri. Kalaupun ada mungkin sangat tidak efisien.
Kita bisa melakukannya dengan prosedur tersimpan dan loop. Dengan indeks yang Anda tambahkan, itu juga harus cukup cepat. Ini menggunakan dua tabel memilih node dari tabel input (A) dan memasukkan node dan anak-anak mereka ke (B). Itu kemudian menukar B untuk A, dan berulang sampai tidak ada lagi node non-daun yang ada di A. Hal yang menyenangkan adalah iterasi loop hanya akan sebanyak level mereka antara node input dan node daun terakhir, yang dalam banyak kasus adalah mungkin tidak terlalu dalam. Prosedur tersimpan ini akan lebih cepat daripada melakukannya secara eksternal dalam kode.
FYI Saya mengalami kesulitan dengan instalasi saya menangani tabel sementara, jika Anda mendapatkan 'kesalahan 2' maka hapus kata kunci sementara.
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);
Saya menggunakan kumpulan sampel berikut untuk pengujian:
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);