1

私がこのテーブルを持っているとしましょう

parent | child 
   1       2        
   1       3        
   2       4        
   4       5        
   5       6        

そして、6が1の子孫であるかどうかを確認したいと思います(これはそうです)... 1つのクエリ内でこれを実行できますか、それとも必然的にすべてのデータを取得してPHPで処理する必要がありますか?

4

3 に答える 3

1

これはツリーです(または、1つのノードに複数の親がある場合はグラフ)...ツリーのすべてのノードは親のみを認識しているため、単一の「ホップ」でツリー構造を逆方向に解析することはできません。

または、このように、ノードからツリーのルートまでのフルパスをノードのdb行に保存する場合に限ります。

parent | child | path
   1       3      3,1
   3       2      2,3,1

等々...

また、これを読むこともできます:ノードがマルチウェイツリー内の別のノードの子孫であるかどうかを判断するためのO(1)アルゴリズム?

于 2012-06-18T21:20:45.740 に答える
1

単一のクエリでこれを行うには、mysql がサポートしていない再帰構文が必要です。Oraclewith ... connect by priorと SqlServer は再帰に CTE (共通テーブル式) を使用します。

基本的に、PHP を使用してクエリと解析を行うか、ストアド プロシージャを使用して一時テーブルを作成し、プログラムで再帰を行う必要があります。

于 2012-06-18T21:26:22.770 に答える
1

PHP でデータを処理しなくても、MySQL で再帰を使用してツリーをたどることができます。ただし、MySQL は真の再帰をサポートしていないため、いくつかの再帰的な手法で解決する必要があります。

この SO question で 1 つの方法が説明されていますが、テーブルを変更する必要があります。

別の方法は、ジョブが完了するまでテーブルをループするストアド関数を使用することです(ある意味で再帰的です)。これはおそらく現在のテーブルで機能しますが、達成するのはより複雑です。

TYPO3 ページ テーブルをたどって、特定のルートラインのすべてのページ ID を検索する例をここに示します (達成しようとしているものと同等です)。

BEGIN
        DECLARE _id INT;
        DECLARE _parent INT;
        DECLARE _next INT;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL;

        SET _parent = @id;
        SET _id = -1;

        IF @id IS NULL THEN
                RETURN NULL;
        END IF;

        LOOP
                SELECT  MIN(uid)
                INTO    @id
                FROM    pages
                WHERE   pid = _parent
                AND uid > _id
                AND deleted = 0
                AND hidden =0;                
                IF @id IS NOT NULL OR _parent = @start_with THEN
                        SET @level = @level + 1;
                        RETURN @id;
                END IF;
                SET @level := @level - 1;
                SELECT  uid, pid
                INTO    _id, _parent
                FROM    pages
                WHERE   uid = _parent
                AND     deleted = 0
                AND     hidden = 0;
        END LOOP;
END

申し訳ありませんが、この例をニーズに合わせて調整する時間がないため、これは不完全な回答になりますが、それでも正しい方向に進むことができることを願っています.

于 2012-06-18T21:30:55.820 に答える