MySQL の階層的再帰クエリを作成するにはどうすればよいですか?
P粉329425839
2023-08-23 21:55:29
<p>私には MySQL テーブルが 1 つあります。以下に示すように:</p>
<テーブルクラス="s-テーブル">
<頭>
<tr>
<th style="text-align:center;">id</th>
<th style="text-align:center;">名前</th>
<th style="text-align:center;">parent_id</th>
</tr>
</頭>
<みんな>
<tr>
<td style="text-align:center;">19</td>
<td style="text-align:center;">类别1</td>
<td style="text-align:center;">0</td>
</tr>
<tr>
<td style="text-align:center;">20</td>
<td style="text-align:center;">类别2</td>
<td style="text-align:center;">19</td>
</tr>
<tr>
<td style="text-align:center;">21</td>
<td style="text-align:center;">类别3</td>
<td style="text-align:center;">20</td>
</tr>
<tr>
<td style="text-align:center;">22</td>
<td style="text-align:center;">类别4</td>
<td style="text-align:center;">21</td>
</tr>
<tr>
<td style="text-align:center;">...</td>
<td style="text-align:center;">...</td>
<td style="text-align:center;">...</td>
</tr>
</tbody>
</テーブル>
<p>现在、我想要一个 MySQL 查询、我们要求的提供 id [例: <code>id=19</code>]、その後我应该获取そのすべての子 id [即結果应该有 id ' 20,21,22']....</p>
<p>子クラスの次の構造は不明です。異なる可能性があります....</p>
<p>我知道 <code>for</code> をどのように使用するかここまで循環してきました...しかし、同じ目的を達成するために単一の MySQL テストをどのように使用しますか?</p>
MySQL 8 の場合: 再帰を使用します 構文を使用します。
MySQL 5.x の場合: インライン変数、パス ID、または自己結合を使用します。
MySQL 8 リーリー
parent_id = 19
で指定した値は、子孫を選択する親のid
共通テーブル式をサポートしていない MySQL のバージョン (バージョン 5.7 まで) の場合、次のクエリを使用してこれを実現できます。 リーリーに設定する必要があります。
MySQL 5.x
これは
ヴァイオリンです。
ここで、 @pv := '19' で指定した値は、子孫を選択する親の
idに設定する必要があります。
これは、親に複数の子がいる場合にも機能します。ただし、各レコードは
parent_id 条件を満たす必要があります。満たさない場合、結果は不完全になります。 p>
最初に
句など、階層ルックアップ用の代替の非標準構文があります。 102/b14200/queries003.htm" rel="noreferrer">Oracle、DB2、Informix、CUBRID a> およびその他のデータベース。クエリ内の変数の割り当て
このクエリは、特定の MySQL 構文を使用します。変数は実行中に割り当てられ、変更されます。実行順序については、いくつかの仮定が行われます:
from
句を評価します。ここで@pv- が初期化されます。
from- エイリアスから取得された順序で各レコードに対して評価されます。したがって、ここで設定する条件には、親が子孫ツリー内にあると識別されているレコードのみが含まれます (主親のすべての子孫が段階的に
この length- 関数は、
警告:
where
句は、@pv
に追加されます)。where
句の条件は順番に評価され、全体的な結果が決定されると評価は中断されます。したがって、2 番目の条件は親リストに ID を追加するため、2 番目の位置になければなりません。これは、ID が最初の条件を通過した場合にのみ発生します。pv
文字列が何らかの理由で false 値を生成した場合でも、この条件が常に true であることを保証するために呼び出されます。全体として、これらの仮定は信頼するには危険すぎると思われるかもしれません。
ドキュメントしたがって、上記のクエリと一致していても、たとえば条件を追加したり、このクエリをより大きなクエリ内のビューまたはサブクエリとして使用したりする場合、評価の順序は変わる可能性があります。これは、将来の MySQL バージョン : で削除される
「機能」です。上で述べたように、MySQL 8.0 以降では、再帰的な with一> 構文を使用する必要があります。
###効率###非常に大規模なデータ セットの場合、この解決策は遅くなる可能性があります。
find_in_set
操作はリスト内の数値を検索する最も理想的な方法ではなく、同じ結果を確実に達成できないためです。返されるレコードの数としての目標。
代替案 1:
再帰を使用する
、接続
再帰クエリの SQL:1999 ISO 標準
WITH [RECURSIVE]
構文 を実装するデータベースが増えています (例: Postgres 8.4 、SQL Server 2005) a>, DB2, Oracle 11gR2 , SQLite 3.8.4 , Firebird 2.1 , H2 , HyperSQL 2.1.0 、Teradata、MariaDB 10.2.2 )。 バージョン 8.0 以降、MySQL もサポートします。使用する構文については、この回答の先頭を参照してください。一部のデータベースには、 CONNECT BY
MySQL バージョン 5.7 はそのような機能を提供しません。データベース エンジンがこの構文を提供する場合、またはこの構文を提供するデータベース エンジンに移行できる場合、これが間違いなく最良の選択です。そうでない場合は、次の代替案を検討してください。
代替 2: パス スタイル識別子
階層情報 (パス) を含む ID 値を割り当てると、作業がはるかに簡単になります。たとえば、あなたの場合、これは次のようになります:
は次のようになります:
リーリー
代替案 3: 繰り返しの自己結合階層ツリーの深さの上限がわかっている場合は、次のような標準の
sqlクエリを使用できます。 リーリー
これを参照してください
フィドルwhere
条件は、どの親の子孫を取得するかを指定します。必要に応じて、このクエリをさらに多くのレベルに拡張できます。