3

以下は私のテーブルにあるものです。

myTable

++++++++++++++++++++
Parent   +  Child
++++++++++++++++++++
  C1     +    G1
  C1     +    G2
  C1     +    G3
  G3     +    D1
  G3     +    D2
  C1     +    G4
  G4     +    D3
  G4     +    D4
  C2     +    G5
  C2     +    G6
  C2     +    G7
  C2     +    G8
 ++++++++++++++++++++

何が欲しいのか、MYSQLを使って以下のようにします。

C1
  G1
  G2
  G3
    D1
    D2
  G4
    D3
    D4

C2
  G5
  G6
  G7
  G8

これがMYSQLで可能かどうか教えてください。出力はTREEのようなものです。

アップデート1

この例を使用できるように、以下のような新しいテーブルを取得した場合も問題ありません。

++++++++++++++++++++++++++++++++++++++++
Parent   +  Child   + PLevel  + CLevel
++++++++++++++++++++++++++++++++++++++++
  C1     +    G1    +   1    +   2
  C1     +    G2    +   1    +   2
  C1     +    G3    +   1    +   2
  G3     +    D1    +   2    +   3
  G3     +    D2    +   2    +   3
  C1     +    G4    +   1    +   2
  G4     +    D3    +   2    +   3
  G4     +    D4    +   2    +   3
  C2     +    G5    +   1    +   2
  C2     +    G6    +   1    +   2
  C2     +    G7    +   1    +   2
  C2     +    G8    +   1    +   2
++++++++++++++++++++++++++++++++++++++++

注:レベルを1から開始しました(たとえば、レベルは0から開始します)。レベルが0から始まるこの新しいテーブルを取得した場合も問題ありません。

4

4 に答える 4

0

MySQLとRDBMSは一般に、この種の構造には適していません。これを行うには、おそらくクライアント側の再帰を使用する必要があります。

例のように、再帰が3つの深さに制限されている場合は、結合を使用してそれを行うことができますが、より深いツリーに対してはあまりスケーラブルではありません。

于 2012-05-21T16:32:31.587 に答える
0

単一のクエリでは実行できませんが、ストアドプロシージャで実行できます...唯一の前提条件として、「C1」と「C2」が存在することを表すために、既存のサンプルテーブルにさらに2つのレコードを追加する必要があります。トップレベル...「親」フィールドが空白で、子レベルが「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
于 2012-05-27T13:50:52.390 に答える
0

最初に、計算レベルの再帰関数を作成します。

function fn_CalcLevel(int @ID) 
As Begin
  Declare @ParentID int
  Select @ParentID = ParentID From Table1 where ID = @ID

  IF (@ParentID IS NULL) Return 1 Else Return 1+fn_CalcLevel(@ParentID)
End

次に、以下のようなクエリを作成します

Select *, fn_CalcLevel(Table1.ID) as Level
From Table1
于 2012-05-28T04:30:18.933 に答える
0

テーブルを少し再構築した場合は、次のようなものを使用できます。

  SELECT Child,CONCAT(LPAD('',Clevel,' '),Child),etc from tablename

再構築では、ルートノードを親ノードが0の行として必要になります。親/子/経営幹部レベルで独自の順序を追加して、必要に応じてシーケンスを取得できます。

これは数年前のことですが、他の人の労力を節約できるかもしれません。

于 2015-11-13T15:17:50.757 に答える