共通テーブル式
共通テーブル式は、名前付きのサブクエリを表します。 テーブル式を使用できるSELECT クエリ内の任意の場所で、名前を使って参照できます。
名前付きサブクエリは、現在のクエリのスコープ内、または子サブクエリのスコープ内で、名前を使って参照できます。
SELECT クエリ内で共通テーブル式を参照すると、CTE が明示的にマテリアライズされていない限り、常にその定義元のサブクエリに置き換えられます (Materialized Common Table Expressions を参照) 。
再帰は、識別子解決の処理で現在の CTE を見えなくすることで防止されます。
CTE は、呼び出されたすべての箇所で同じ結果になることを保証しない点に注意してください。これは、使用されるたびにクエリが再実行されるためです。
構文
例
サブクエリが再実行されるケースの例:1000000 が表示されるはずです
しかし、cte_numbers を 2 回参照しているため、そのたびに乱数が生成され、結果として 280501, 392454, 261636, 196227 など、毎回異なる値が表示されます…
マテリアライズド共通テーブル式
デフォルトでは、ClickHouse は CTE のサブクエリを参照箇所ごとにインライン展開し、参照のたびに再実行します。MATERIALIZED キーワードを追加すると、ClickHouse は CTE のサブクエリを 一度だけ 実行し、その結果を一時テーブルに格納して、以降のすべての参照でそのテーブルを使用します。
これは、同じ CTE が 1 つのクエリ内で複数回参照される場合 (たとえば自己結合や複数の IN サブクエリ) に特に有用です。元の計算が一度しか行われないためです。
マテリアライズド CTE は 実験的 な機能です。
利用するには、設定
enable_materialized_cte が有効になっている必要があります。
設定が無効の場合、MATERIALIZED キーワードは無視されます。CTE は通常の CTE と同様に参照ごとにインライン展開され、警告がログに記録されます。構文
マテリアライズド CTEを使用する場面
マテリアライズド CTEが特に有効なのは、次のような場合です。- 1つのクエリ内で同じCTEが複数回参照される場合。
MATERIALIZEDを使用しないと、参照のたびにサブクエリがそれぞれ再実行されます。 - CTEに
generateRandomのような非決定論的関数が含まれている場合。 マテリアライズすることで、すべての参照で同じデータを参照できます。 - CTEに、繰り返し実行すべきでない高コストな計算 (集計、JOIN、大規模スキャン) が含まれている場合。
例
例 1: マテリアライズド CTEに対する自己結合MATERIALIZED がない場合、JOIN の両側でそれぞれ独立にサブクエリが実行されます。
MATERIALIZED がある場合、テーブルは一度だけスキャンされ、JOIN の両側は同じ一時テーブルを読み取ります。
generateRandom を使うと、参照するたびに異なる結果になります。
CTE をマテリアライズすると、一貫した結果が得られます:
1000000 になります。
例 3: 実体化された CTE のチェーン
実体化された CTE は、別の実体化された CTE を参照できます。
ClickHouse は依存関係を解決し、それらを正しい順序で実体化します。
制限事項
- 実験的な設定が必要: 設定
enable_materialized_cteを有効にする必要があります。無効の場合、MATERIALIZEDキーワードは無視され、CTE は通常の CTE と同様に参照ごとにインライン展開され、警告が記録されます。 RECURSIVEでは未サポート:MATERIALIZEDキーワードとRECURSIVEキーワードを組み合わせることはできず、UNSUPPORTED_METHOD例外が発生します。- 相関 CTE は使用不可: マテリアライズド CTE では、外側のクエリスコープのカラムを参照できません。
共通スカラ式
ClickHouse では、WITH 句で任意のスカラ式に別名を定義できます。
共通スカラ式は、クエリ内のどの場所からでも参照できます。
構文
例
例 1: 定数式を”変数”として使うextension は gen_name ラムダ関数の本体内では束縛されていません。
extension は generated_names の定義および使用のスコープでは共通スカラ式として '.txt' に定義されていますが、generated_names サブクエリ内で利用可能であるため、テーブル extension_list のカラムとして解決されます。
SELECT句のカラムリストから sum(bytes) 式の結果を除外する
再帰クエリ
オプションのRECURSIVE修飾子を使うと、WITHクエリ内でそのクエリ自身の出力を参照できます。例:
例: 1 から 100 までの整数の合計
再帰 CTE は、バージョン
24.3 で導入された クエリアナライザ に依存しています。クエリアナライザは、そのバージョン以降はデフォルトで有効であり、26.9 以降は必須です。インスタンス、ロール、またはプロファイルでアナライザが無効になっている古いバージョンでは、再帰 CTE は (UNKNOWN_TABLE) または (UNSUPPORTED_METHOD) 例外を送出します。その場合は enable_analyzer 設定を有効にするか、アップグレードしてください。WITH クエリの一般的な形式は、常に非再帰項、続いて UNION ALL、その後に再帰項が続く形です。このうち、クエリ自身の出力への参照を含められるのは再帰項だけです。再帰 CTE クエリは次のように実行されます。
- 非再帰項を評価します。非再帰項クエリの結果を一時的な作業テーブルに格納します。
- 作業テーブルが空でない限り、次の手順を繰り返します。
- 再帰項を評価し、再帰的な自己参照を作業テーブルの現在の内容に置き換えます。再帰項クエリの結果を一時的な中間テーブルに格納します。
- 作業テーブルの内容を中間テーブルの内容で置き換え、その後、中間テーブルを空にします。
検索順序
深さ優先の順序を作成するには、各結果行について、これまでに訪問した行の Array を計算します。 例: 木構造の深さ優先走査順サイクル検出
まず、グラフ用のテーブルを作成します。Maximum recursive CTE evaluation depth エラーで失敗します。
無限クエリ
外側のクエリでLIMIT を使用する場合は、無限再帰 CTE クエリも使用できます。
例: 無限再帰 CTE クエリ
末尾のカンマ
WITH句では、最後の要素の後にもカンマを付けられます。