Aunque no puede hacerlo con una sola consulta, puede hacerlo con un procedimiento almacenado ... El único requisito previo es que debe agregar 2 registros más a su tabla de muestra existente para representar que "C1" y "C2" SON el nivel superior... Agregue un registro donde el campo "Principal" esté en blanco, y el nivel secundario sea "C1" y otro para "C2". Esto "preparará" el nivel principal superior. para la asociación de jerarquía posterior, de lo contrario no tiene "base" inicial de la jerarquía de nivel superior. También requiere una columna de "clave principal" (que he creado en este script como "IDMyTable", que es solo secuencial 1-x, pero supondría que tiene una columna de incremento automático en su tabla para usar en su lugar).
Incluí todas las columnas de salida para mostrar CÓMO se construye, pero la premisa de esta rutina es crear una tabla basada en las salidas de columna esperadas, pero extra para mantener la representación jerárquica aguas abajo a medida que se construye. Para ASEGURARME de que conserven la orientación correcta a medida que las capas se hacen más profundas, estoy concatenando la columna "ID". Verá cómo funciona en el conjunto de resultados final.
Luego, en el conjunto de resultados final, estoy rellenando previamente los espacios en función de la profundidad de los datos de la jerarquía.
El ciclo agregará cualquier registro en función de que su padre se encuentre en el conjunto de resultados anterior, pero solo si la ID aún no se ha agregado (evitar duplicados)...
Para ver cómo se agregó constantemente el orden cíclico, puede ejecutar la última consulta SIN el orden y ver cómo se calificó cada iteración y se agregó el nivel de jerarquía anterior...
-- --------------------------------------------------------------------------------
-- 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