Không có cách nào để làm điều này trong một truy vấn duy nhất. Ngay cả khi có nó có lẽ sẽ rất kém hiệu quả.
Chúng ta có thể làm điều đó với một thủ tục được lưu trữ và một vòng lặp. Với các chỉ mục bạn đã thêm, nó cũng sẽ khá nhanh chóng. Điều này sử dụng hai bảng chọn các nút từ bảng đầu vào (A) và chèn nút và các nút con của chúng vào (B). Sau đó, nó hoán đổi B cho A và lặp lại cho đến khi không còn nút không phải lá nào nữa tồn tại trong A. Điều thú vị là các lần lặp vòng lặp sẽ chỉ nhiều bằng mức của chúng giữa nút đầu vào và nút lá cuối cùng, trong hầu hết các trường hợp là có lẽ không sâu như vậy. Quy trình được lưu trữ này sẽ nhanh hơn so với thực hiện bên ngoài trong mã.
FYI Tôi gặp khó khăn trong quá trình cài đặt của mình khi xử lý các bảng tạm thời, nếu bạn gặp 'lỗi 2', hãy xóa từ khóa tạm thời.
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);
Tôi đã sử dụng bộ mẫu sau để thử nghiệm:
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);