尽管您不能使用单个查询,但可以使用存储过程...唯一的前提条件是,您需要在现有示例表中再添加 2 条记录以表示“C1”和“C2”是顶层...添加一条记录,其中“父”字段为空白,子级别为“C1”,另一个为“C2”。这将“准备”最顶层的父级。对于后续的层次关联,否则你没有顶层层次的起始“基础”。它还需要一个“主键”列(我在此脚本中将其创建为“IDMyTable”,它只是 1-x 连续的,但假设您的表上有一个自动增量列可供使用)。
我已经包含了所有输出列以显示它是如何构建的,但此例程的前提是根据预期的列输出创建一个表,但在构建时还额外保存下游的分层表示。为了确保它们在层变深时保持正确的方向,我连接了“ID”列——你会看到它在最终结果集中是如何工作的。
然后,在最终结果集中,我根据层次结构数据的深度预先填充空间。
循环将根据在前面结果集中找到的父记录添加任何记录,但前提是尚未添加 ID(防止重复)...
要查看循环顺序是如何不断附加的,您可以运行最后一个查询而不使用 order by,并查看每次迭代如何限定并添加上一个层次结构级别...
-- --------------------------------------------------------------------------------
-- 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