単一のクエリでは実行できませんが、ストアドプロシージャで実行できます...唯一の前提条件として、「C1」と「C2」が存在することを表すために、既存のサンプルテーブルにさらに2つのレコードを追加する必要があります。トップレベル...「Parent」フィールドが空白で、子レベルが「C1」で、もう1つが「C2」であるレコードを追加します。これにより、最上位の親レベルが「準備」されます。後続の階層の関連付けのために、そうでない場合は、最上位階層の開始「基礎」がありません。また、「主キー」列も必要です(このスクリプトでは、「IDMyTable」として1倍のシーケンシャルで作成しましたが、代わりに使用するためにテーブルに自動インクリメント列があると想定しています)。
構築方法を示すためにすべての出力列を含めましたが、このルーチンの前提は、期待される列出力に基づいてテーブルを作成することですが、構築中に階層表現をダウンストリームに保持するために追加されます。レイヤーが深くなるにつれて正しい方向を維持することを確認するために、「ID」列を連結しています。最終的な結果セットでどのように機能するかを確認できます。
次に、最終的な結果セットで、階層データの深さに基づいてスペースを事前にパディングします。
ループは、前の結果セットで見つかった親に基づいてレコードを追加しますが、IDがまだ追加されていない場合に限ります(重複を防止します)...
循環順序が常に追加される方法を確認するには、順序なしで最後のクエリを実行し、各反復がどのように修飾され、前の階層レベルが追加されたかを確認します...
-- --------------------------------------------------------------------------------
-- 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