Mặc dù bạn không thể thực hiện với một truy vấn duy nhất, nhưng bạn có thể thực hiện với một thủ tục được lưu trữ ... Yêu cầu trước duy nhất, bạn cần thêm 2 bản ghi nữa vào bảng mẫu hiện có của mình để thể hiện rằng "C1" và "C2" LÀ cấp cao nhất ... Thêm bản ghi trong đó trường "Gốc" để trống và cấp con là "C1" và một bản ghi khác cho "C2". Điều này sẽ "chuẩn bị" cấp phụ huynh cao nhất. cho liên kết phân cấp tiếp theo, nếu không, bạn không có "cơ sở" bắt đầu của phân cấp cấp cao nhất. Nó cũng yêu cầu cột "khóa chính" (mà tôi đã tạo trong tập lệnh này là "IDMyTable" chỉ là 1-x tuần tự, nhưng sẽ giả sử bạn có cột tăng tự động trên bảng của mình để sử dụng thay thế).
Tôi đã bao gồm tất cả các cột đầu ra để hiển thị CÁCH nó được xây dựng, nhưng tiền đề của quy trình này là tạo một bảng dựa trên kết quả đầu ra cột dự kiến, nhưng thêm vào đó để giữ biểu diễn phân cấp ở phía dưới khi nó đang được xây dựng. Để ĐẢM BẢO chúng vẫn giữ đúng hướng khi các lớp sâu hơn, tôi đang ghép cột "ID" - bạn sẽ thấy nó hoạt động như thế nào trong tập kết quả cuối cùng.
Sau đó, trong tập kết quả cuối cùng, tôi đặt trước các khoảng trắng dựa trên dữ liệu phân cấp sâu đến đâu.
Vòng lặp sẽ thêm bất kỳ bản ghi nào dựa trên bản ghi gốc của chúng được tìm thấy trong tập kết quả trước đó, nhưng chỉ khi ID chưa được thêm (ngăn trùng lặp) ...
Để xem thứ tự theo chu kỳ liên tục được thêm vào như thế nào, bạn có thể chạy truy vấn cuối cùng KHÔNG theo thứ tự và xem mỗi lần lặp đủ điều kiện và đã thêm mức phân cấp trước đó đã được áp dụng như thế nào ...
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `GetHierarchy2`()
BEGIN
-- prepare a hierarchy level variable
set @hierlvl := 00000;
-- prepare a variable for total rows so we know when no more rows found
set @lastRowCount := 0;
-- pre-drop temp table
drop table if exists MyHierarchy;
-- now, create it as the first level you want...
-- ie: a specific top level of all "no parent" entries
-- or parameterize the function and ask for a specific "ID".
-- add extra column as flag for next set of ID's to load into this.
create table MyHierarchy as
select
t1.IDMyTable,
t1.Child AS Parent,
@hierlvl as IDHierLevel,
cast( t1.IDMyTable as char(100)) FullHierarchy
from
MyTable t1
where
t1.Parent is null
OR t1.Parent = '';
-- how many rows are we starting with at this tier level
set @lastRowCount := ROW_COUNT();
-- we need to have a "primary key", otherwise our UPDATE
-- statement will nag about an unsafe update command
alter table MyHierarchy add primary key (IDMyTable);
-- NOW, keep cycling through until we get no more records
while @lastRowCount > 0 do
-- NOW, load in all entries found from full-set NOT already processed
insert into MyHierarchy
select
t1.IDMyTable,
t1.Child as Parent,
h1.IDHierLevel +1 as IDHierLevel,
concat_ws( ',', h1.FullHierarchy, t1.IDMyTable ) as FullHierarchy
from
MyTable t1
join MyHierarchy h1
on t1.Parent = h1.Parent
left join
MyHierarchy h2
on t1.IDMyTable = h2.IDMyTable
where
h2.IDMyTable is null;
set @lastRowCount := row_count();
-- now, update the hierarchy level
set @hierLevel := @hierLevel +1;
end while;
-- return the final set now
select
*, concat( lpad( ' ', 1 + (IDHierLevel * 3 ), ' ' ), Parent ) as ShowHierarchy
from MyHierarchy
order by FullHierarchy;
END