この質問は、SQL全般に関するものです。特にMySQLに回答することは役立ちますが、必須ではありません。
わかりました、これを言葉で表すのに苦労しています...我慢してください。
私はもののツリー(ノードと呼びます)があり、次のようなテーブルがあるとします(構造は変更できます。これは単純なバージョンです)。
+---------+-----------+
| node_id | parent_id |
+---------+-----------+
| 1 | NULL |
| 2 | NULL |
| 3 | 1 |
| 4 | 1 |
| 5 | 5 |
| 7 | 2 |
| 8 | 5 |
+---------+-----------+
次に、エンティティのテーブルがあります。各エンティティは特定のノードに関連付けられています。たとえば(ここでも、構造を変更できます):
+-----------+---------+
| entity_id | node_id |
+-----------+---------+
| 1 | 1 |
| 2 | 1 |
| 3 | 4 |
| 4 | 7 |
| ...many more rows |
+-----------+---------+
この構造は、多くのことを表すことができます。各エンティティは映画ですが、各ノードはジャンルです(ただし、サブジャンルのレベルは無制限にできます)。
したがって、特定のノードのすべてのエンティティを取得するのは簡単です。指定したnode_id
のエンティティテーブルでクエリを実行するだけです。
これが私の質問です。特定のノードに関連付けられているすべてのエンティティをエンティティテーブルにどのようにクエリしますかandすべての子ノード(すべてのレベル、再帰的に)。映画の例では、特定のジャンルとそのすべてのサブジャンル、およびそのサブジャンルなどのすべての映画を検索します。
Wordを再帰的に説明しましたが、クエリが再帰的である必要があるという意味ではありませんが、概念的にはそうです。クエリは可能な限り高速である必要があります。テーブルの構造も変更する必要がある場合があります。
ご協力いただきありがとうございます!
行(5,5)はタイプミスだと思っているので、次のように使用しました。
create table tree (node_id int not null primary key, parent_id int);
insert into tree (node_id, parent_id)
values (1,null),(2,(null),(3,1),(4,1),(5,4),(7,2),(8,5);
補足として、質問への回答、質問のアスキーアート、または上記のようなステートメントの作成と挿入を開始する場合は、どの表現を使用しますか?
ツリーを再帰的にトラバースするには、再帰的な共通テーブル式(CTE)を使用できます。
with rec (node_id, ancestor_id) as (
select t.node_id, t.parent_id
from tree t
union all
select rec.node_id, t.parent_id
from rec, tree t
where rec.ancestor_id = t.node_id
) select * from rec
私は明示的な結合を好みますが、使用しているDBMSはCTEでそれらをサポートしていません。
with rec (node_id, ancestor_id) as (
select t.node_id, t.parent_id
from tree t
union all
select rec.node_id, t.parent_id
from rec
join tree t
on rec.ancestor_id = t.node_id
) select * from rec
今度は、この結果をエンティティテーブルに結合するだけです。
with rec (node_id, ancestor_id) as (
select t.node_id, t.parent_id
from tree t
union all
select rec.node_id, t.parent_id
from rec
join tree t
on rec.ancestor_id = t.node_id
) select rec.ancestor_id, e,entity_id
from rec
join entities e
on e.node_id = rec.node_id
これは、DBMSバージョンが再帰的なCTEをサポートしていることを前提としています。 MySQL/MariaDBの最新バージョンがサポートしています。
もう1つの注意点として、ツリーの関係を正規化し、構造を別の関係に維持することができます。
create table treenode (node_id int not null primary key, ...)
create table tree (node_id int not null primary key
,parent_id int not null);
ルートノードは、ツリーに存在しないノードです
古いバージョンを使用している場合、または大量のデータがあり、パフォーマンスを改善する必要がある場合は、モデルに情報を追加できます。最も一般的なものは次のとおりです。