再帰的自己結合


15

私はcommentsこれを単純化できるテーブルを持っています:

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

where parent_idはnull入力可能ですが、親コメントのキーになる場合があります。


さて、select特定のコメントのすべての子孫はどうすればいいですか?
コメントはいくつかのレベル下にあるかもしれません...

回答:


16

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

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

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

隣接リスト(つまり、列)以外のモデルで階層データを保存する方法については、https//stackoverflow.com/questions/192220/what-is-the-most-efficient-を参照してください。エレガントな方法でフラットテーブルにツリーを解析する/

幸運を!


2番目のリンクのその解決策はどのように危険なのでしょうか。説明してもらえますか?それ以外の場合は、サイトへようこそ!
-dezso

3
@dezso:クエリの作成者であるQuassnoiは、「MySQLはセッション変数の動作を明確に定義していないため、アップグレードしても安全ではありません。ただし、クエリ内でタイムリーに隣接リストを処理する唯一の方法です。」危険という言葉は強すぎるかもしれませんが(潜在的に不安定なのでしょうか?)、私は注意を払うことを好みます(さらに、MySQLよりもOracleの方が詳しいので、さらに慎重になりたいと思いました)。ところで、歓迎してくれてありがとう!私は、SEネットワークの長年の潜伏者であり、少し返済する時だと判断しました。
バルモア

2
WITH [RECURSIVE]構文がmysql 8.0からサポートされるようになりました。dev.mysql.com/doc/refman/8.0/en/with.html
ClearCrescendo

6

このテーブルデザインは、ビルカーウィン(SQL Antipatterns Strike Backプレゼンテーションのスライド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を使用します(ただし、これはほとんどの場合、オプションではありません)


2
ここでビル・カーウィンに同意しません。隣接モデルはアンチパターンではありません。再帰クエリをサポートする最新のDBMS(オラクルは20年以上にわたってこれをサポートしてきました)を使用すると、このようなモデルは検索更新に非常に効率的です。
a_horse_with_no_name

5

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

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

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

要するに、私が作成したストアドプロシージャは、キュー処理を使用して先行予約ツリートラバーサルを実行します

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

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

  • STEP01)で始まる parent_idキュー内で
  • STEP02)次をデキュー parent_idを現行として
  • STEP03)すべてをキューに入れる id現在の値をparent_id
  • STEP04)コメントの印刷または収集
  • STEP05)キューが空でない場合、ジャンプ STEP02
  • STEP06)完了です!!!

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

  • STEP01)で始まる idキュー内で
  • STEP02)次をデキュー idを現行として
  • STEP03)エンキュー parent_id現在の値をid
  • STEP04)コメントの印刷または収集
  • STEP05)キューが空でない場合、ジャンプ STEP02
  • STEP06)完了です!!!

実装を確認するには、他の投稿のストアドプロシージャをご覧ください。

試してみる !!!


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.