web-dev-qa-db-ja.com

再帰的な自己結合

私はcommentsテーブルを持っています、これはこれに簡略化できます:

comments
=======
id
user_id
text
parent_id

どこ parent_idはnull可能ですが、その親コメントのキーになる可能性があります。


では、特定のコメントのすべての子孫をどのようにselectできますか?
コメントは数レベル下になる可能性があります...

15
Josh

階層クエリ (再帰クエリは既知であるため)は、MySQLではサポートされていません。

ただし、これらはOracle、Microsoft SQL Server、DB2、PostgreSQLなどでサポートされています。

回避策が必要な場合は、動的な(したがって、潜在的に危険な)トリックをここで見つけることができます: https://stackoverflow.com/questions/8104187/mysql-hierarchical-queries

また、隣接リスト(すなわち、Parent列)ここ: https://stackoverflow.com/questions/192220/what-is-the-most-efficient-elegant-way-to-parse-a-flat-table-into- a-tree /

幸運を!

16
Valmoer

このテーブルデザインは、Bill Karwinが説明したSQLアンチパターン「ナイーブツリー」です(スライド48から SQLアンチパターンの反撃 プレゼンテーションにあります)。この設計の問題は、特にノードのすべての子孫(または親)を取得するのが難しいことです。 MySQLを使用しているため、他のRDBMSに存在する共通のテーブル式(WITHステートメントとそのRECURSIVE修飾子)は使用できません。

残っているのは:

  • 階層データ構造の代替実装を使用します( この質問 への回答は、これについての良い参考になるかもしれません)
  • 深さ制限付きの自己結合クエリを作成します。 depth = 5の場合、次の行で何かを使用できます。

    SELECT *
    FROM comments AS c1
      JOIN comments AS c2 ON (c2.parent_id = c1.id)
      JOIN comments AS c3 ON (c3.parent_id = c2.id)
      JOIN comments AS c4 ON (c4.parent_id = c3.id)
      JOIN comments AS c5 ON (c5.parent_id = c4.id)
    
  • wITH RECURSIVEをサポートするRDBMSを使用します(これはほとんどの人にとって選択肢ではありませんが)

7
redguy

MySQLは、必要なクエリなどの再帰クエリをサポートしていません。

しばらく前に行ったのは、そのためのモデルを提供するストアドプロシージャを作成することでした。

ホイールを再発明するのではなく、これに関する私の過去の投稿へのリンクを提供します。

簡単に言うと、私が作成したストアドプロシージャは、キュー処理を使用してツリートラバーサルをプレオーダーします。

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

すべての子の親(GetFamilyTreeストアドプロシージャなど)

  • STEP01)キューのparent_idから始めます
  • STEP02)次のparent_idを現在のものとしてデキュー
  • STEP03)現在のparent_idを持つすべてのid値をエンキューします
  • STEP04)コメントを印刷または収集する
  • STEP05)キューが空でない場合は、STEP02に移動します
  • STEP06)完了です!!!

すべての親に対する子(GetAncestryストアドプロシージャなど)

  • STEP01)キューのidから始めます
  • STEP02)次のidを現在のものとしてデキューします
  • STEP03)現在のidparent_id値をエンキューします
  • STEP04)コメントを印刷または収集する
  • STEP05)キューが空でない場合は、STEP02に移動します
  • STEP06)完了です!!!

他の投稿でストアドプロシージャを調べて、実装を確認してください。

試してみる !!!

5
RolandoMySQLDBA
SELECT  group_concat(@id :=
        (
        SELECT  id
        FROM    comments
        WHERE   parent_id = @id
        )) AS comment
FROM    (
        SELECT  @id := 1
        ) vars
STRAIGHT_JOIN
        comments
WHERE   @id IS NOT NULL

フィドル

2