VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
SELECT にはできません。
始める前に、mysql -u root -p sakila でクライアントを開いてください。
再帰 CTE の仕組み
CTE_NAME を結果の名前に、COLUMN_NAME を CTE が生成する列に、SEED_VALUE を
開始値に、NEXT_EXPRESSION を前の行から次の行を作る式に、STOP_CONDITION を
いずれ偽になる条件に置き換えます。
再帰 CTE には、UNION ALL でつながれた 2 種類の部分があります。
- シード。アンカーメンバーとも呼ばれ、CTE をまったく参照せず、開始行を 生成します。
- 再帰メンバー。CTE 自身から選択します。
UNION ALL の代わりに UNION も
受け入れます。UNION は各ラウンドの重複を取り除きます。どちらも一般的では
ありませんが、出会ったときにそれと分かるようにしておく価値はあります。
サーバーはシードを実行し、次に前のラウンドが生成したものに対して再帰部分を
実行します。これを、あるラウンドが行を 1 つも生成しなくなるまで繰り返します。
再帰部分の WHERE が、いずれそれを起こすものです。
キーワードは WITH RECURSIVE で、CTE ではなく WITH に付けます。
5 まで数える
WHERE n < 5 が次の行を
生成しないためです。
このような連番は見た目以上に役に立ちます。実データと結合すると、何も起きな
かった日も含めて範囲内のすべての日に 1 行ずつが得られます。これはデータだけに
対するクエリでは生成できません。
停止条件を省く
WHERE を取り除くと、再帰部分は常に次の行を生成します。
ERROR 3636 は、まず停止条件の欠落または誤りとして読んでください。
SET SESSION cte_max_recursion_depth = 5000; で制限を上げるのが正しいのは、
デフォルトが許すより多くのラウンドが本当に必要なときだけです。クエリが
そもそも止まらないものだった場合、それは誤りです。失敗するまでの時間が
長くなるだけで、結局は失敗します。この設定は変数なので、上の 1,000 は
MySQL の固定の性質ではなく、このサーバーの値です。
まとめ
- CTE が自分自身を読むときは
WITH RECURSIVEと書きます。 - シード部分と再帰メンバーを与え、
UNION ALLでつなぎます。 - 停止条件は再帰部分の
WHEREに置きます。 ERROR 3636は、設定に手を伸ばす前に、暴走した再帰として読みます。
関連項目
- 共通テーブル式 — 再帰しない種類
- UNION — 2 つの部分をつなぐ演算子
- MySQL の CTE が派生テーブルより優れる場合 — オプティマイザがそれらをどう扱うか