私がこのテーブルを持っているとしましょう
parent | child
1 2
1 3
2 4
4 5
5 6
そして、6が1の子孫であるかどうかを確認したいと思います(これはそうです)... 1つのクエリ内でこれを実行できますか、それとも必然的にすべてのデータを取得してPHPで処理する必要がありますか?
私がこのテーブルを持っているとしましょう
parent | child
1 2
1 3
2 4
4 5
5 6
そして、6が1の子孫であるかどうかを確認したいと思います(これはそうです)... 1つのクエリ内でこれを実行できますか、それとも必然的にすべてのデータを取得してPHPで処理する必要がありますか?
これはツリーです(または、1つのノードに複数の親がある場合はグラフ)...ツリーのすべてのノードは親のみを認識しているため、単一の「ホップ」でツリー構造を逆方向に解析することはできません。
または、このように、ノードからツリーのルートまでのフルパスをノードのdb行に保存する場合に限ります。
parent | child | path
1 3 3,1
3 2 2,3,1
等々...
また、これを読むこともできます:ノードがマルチウェイツリー内の別のノードの子孫であるかどうかを判断するためのO(1)アルゴリズム?
単一のクエリでこれを行うには、mysql がサポートしていない再帰構文が必要です。Oraclewith ... connect by prior
と SqlServer は再帰に CTE (共通テーブル式) を使用します。
基本的に、PHP を使用してクエリと解析を行うか、ストアド プロシージャを使用して一時テーブルを作成し、プログラムで再帰を行う必要があります。
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
申し訳ありませんが、この例をニーズに合わせて調整する時間がないため、これは不完全な回答になりますが、それでも正しい方向に進むことができることを願っています.