メインコンテンツへスキップ
ClickHouse は、共通テーブル式 (CTE) 、共通スカラ式、再帰クエリをサポートしています。

共通テーブル式

共通テーブル式は、名前付きのサブクエリを表します。 テーブル式を使用できる SELECT クエリ内の任意の場所で、名前を使って参照できます。 名前付きサブクエリは、現在のクエリのスコープ内、または子サブクエリのスコープ内で、名前を使って参照できます。 SELECT クエリ内で共通テーブル式を参照すると、CTE が明示的にマテリアライズされていない限り、常にその定義元のサブクエリに置き換えられます (Materialized Common Table Expressions を参照) 。 再帰は、識別子解決の処理で現在の CTE を見えなくすることで防止されます。 CTE は、呼び出されたすべての箇所で同じ結果になることを保証しない点に注意してください。これは、使用されるたびにクエリが再実行されるためです。

構文

サブクエリが再実行されるケースの例:
CTE がコードの一部ではなく、結果そのものを正確に受け渡すのであれば、常に 1000000 が表示されるはずです しかし、cte_numbers を 2 回参照しているため、そのたびに乱数が生成され、結果として 280501, 392454, 261636, 196227 など、毎回異なる値が表示されます…

マテリアライズド共通テーブル式

デフォルトでは、ClickHouse は CTE のサブクエリを参照箇所ごとにインライン展開し、参照のたびに再実行します。 MATERIALIZED キーワードを追加すると、ClickHouse は CTE のサブクエリを 一度だけ 実行し、その結果を一時テーブルに格納して、以降のすべての参照でそのテーブルを使用します。 これは、同じ CTE が 1 つのクエリ内で複数回参照される場合 (たとえば自己結合や複数の IN サブクエリ) に特に有用です。元の計算が一度しか行われないためです。
マテリアライズド CTE は 実験的 な機能です。 利用するには、アナライザ が必要であり、設定 enable_materialized_cte も有効になっている必要があります。

構文

マテリアライズド CTEを使用する場面

マテリアライズド CTEが特に有効なのは、次のような場合です。
  • 1つのクエリ内で同じCTEが複数回参照される場合。 MATERIALIZED を使用しないと、参照のたびにサブクエリがそれぞれ再実行されます。
  • CTEに generateRandom のような非決定論的関数が含まれている場合。 マテリアライズすることで、すべての参照で同じデータを参照できます。
  • CTEに、繰り返し実行すべきでない高コストな計算 (集計、JOIN、大規模スキャン) が含まれている場合。
マテリアライズド CTEが1回しか参照されない場合、ClickHouse は不要なオーバーヘッドを避けるため、自動的に通常のサブクエリとしてインライン展開します。

例 1: マテリアライズド CTEに対する自己結合 MATERIALIZED がない場合、JOIN の両側でそれぞれ独立にサブクエリが実行されます。 MATERIALIZED がある場合、テーブルは一度だけスキャンされ、JOIN の両側は同じ一時テーブルを読み取ります。
例 2: 非決定論的関数で決定論的な結果を得る 通常の CTE で generateRandom を使うと、参照するたびに異なる結果になります。 CTE をマテリアライズすると、一貫した結果が得られます:
どちらの参照も同じ実体化済みデータを読み取るため、結果は常に 1000000 になります。 例 3: 実体化された CTE のチェーン 実体化された CTE は、別の実体化された CTE を参照できます。 ClickHouse は依存関係を解決し、それらを正しい順序で実体化します。
CTE の定義順は問いません — 前方参照が可能です:

制限事項

  • 実験的な設定が必要: 設定 enable_materialized_cte を有効にする必要があります。
  • アナライザが必要: マテリアライズド CTE は、アナライザ が有効な場合にのみ動作します (enable_analyzer = 1) 。
  • RECURSIVE では未サポート: MATERIALIZED キーワードと RECURSIVE キーワードを組み合わせることはできず、UNSUPPORTED_METHOD 例外が発生します。
  • 相関 CTE は使用不可: マテリアライズド CTE では、外側のクエリスコープのカラムを参照できません。

共通スカラ式

ClickHouse では、WITH 句で任意のスカラ式に別名を定義できます。 共通スカラ式は、クエリ内のどの場所からでも参照できます。
共通スカラ式が定数リテラル以外を参照している場合、その式によって 自由変数 が生じることがあります。 ClickHouse はあらゆる識別子を可能な限り最も近いスコープで解決するため、名前の衝突があると、自由変数が意図しないエンティティを参照したり、相関サブクエリにつながったりする場合があります。 式中の識別子解決をより予測しやすくするには、使用するすべての識別子を束縛した ラムダ関数 として CSE を定義することを推奨します (これは アナライザ が有効な場合にのみ可能です) 。

構文

例 1: 定数式を”変数”として使う
例 2: 高階関数を使って識別子の範囲を限定する
例 3: 高階関数で自由変数を使用する 次のクエリ例は、束縛されていない識別子が、最も近いスコープ内のエンティティに解決されることを示しています。 ここでは、extensiongen_name ラムダ関数の本体内では束縛されていません。 extensiongenerated_names の定義および使用のスコープでは共通スカラ式として '.txt' に定義されていますが、generated_names サブクエリ内で利用可能であるため、テーブル extension_list のカラムとして解決されます。
例 4: SELECT句のカラムリストから sum(bytes) 式の結果を除外する
例 5: スカラーサブクエリの結果を使用する
例 6: サブクエリで式を再利用する

再帰クエリ

オプションのRECURSIVE修飾子を使うと、WITHクエリ内でそのクエリ自身の出力を参照できます。例: 例: 1 から 100 までの整数の合計
再帰 CTE は、バージョン 24.3 で導入された クエリアナライザ に依存しています。24.3+ を使用していて (UNKNOWN_TABLE) または (UNSUPPORTED_METHOD) 例外が発生する場合は、インスタンス、ロール、またはプロファイルでアナライザが無効になっている可能性があります。アナライザを有効にするには、設定 allow_experimental_analyzer を有効にするか、compatibility 設定をより新しいバージョンに更新してください。 バージョン 24.8 以降、アナライザは正式機能となり、設定 allow_experimental_analyzerenable_analyzer に名称変更されました。
再帰 WITH クエリの一般的な形式は、常に非再帰項、続いて UNION ALL、その後に再帰項が続く形です。このうち、クエリ自身の出力への参照を含められるのは再帰項だけです。再帰 CTE クエリは次のように実行されます。
  1. 非再帰項を評価します。非再帰項クエリの結果を一時的な作業テーブルに格納します。
  2. 作業テーブルが空でない限り、次の手順を繰り返します。
    1. 再帰項を評価し、再帰的な自己参照を作業テーブルの現在の内容に置き換えます。再帰項クエリの結果を一時的な中間テーブルに格納します。
    2. 作業テーブルの内容を中間テーブルの内容で置き換え、その後、中間テーブルを空にします。
再帰クエリは通常、階層データや木構造データを扱うために使用されます。たとえば、木の走査を行うクエリを記述できます。 例: 木の走査 まず、木構造のテーブルを作成します。
次のようなクエリを使って、それらの木構造を走査できます。 例: 木構造の走査

検索順序

深さ優先の順序を作成するには、各結果行について、これまでに訪問した行の Array を計算します。 例: 木構造の深さ優先走査順
幅優先の順序を作るには、探索の深さを追跡するカラムを追加するのが一般的です。 例: 木構造の幅優先走査順

サイクル検出

まず、グラフ用のテーブルを作成します。
このグラフは、次のようなクエリでたどることができます。 例: サイクル検出なしのグラフ走査
ただし、そのグラフに閉路を追加すると、先ほどのクエリは Maximum recursive CTE evaluation depth エラーで失敗します。
循環を処理する標準的な方法は、すでに訪問したノードの配列を計算することです。 例: 循環検出付きのグラフ走査

無限クエリ

外側のクエリで LIMIT を使用する場合は、無限再帰 CTE クエリも使用できます。 例: 無限再帰 CTE クエリ

末尾のカンマ

WITH句では、最後の要素の後にもカンマを付けられます。
最終更新日 2026年6月10日