【しーてぃーいー】

CTE(共通テーブル式) とは?

最終更新:
💡 SQLの途中の結果に名前を付けて、文の中で使う

WITH句で、1つのSQL文の中で参照できる結果に名前を付ける共通テーブル式。読みやすく分ける用途、再帰CTE、一時テーブルやビューとの違い、性能が実行計画に依存する理由を解説します。

📌 このページのポイント
CTE:SQL文の中で結果に名前を付ける1つのSQL文の中だけで有効WITH totals AS (...)集計する部分にtotalsという名前SELECT ... FROM totals後ろのクエリでその名前を参照物理的な一時テーブルの作成とは別実際の計算方法はDBと実行計画による同じ名前の参照 ≠ 必ず1回だけ計算
矢印は定義した結果を参照する関係で、物理的な実行順ではありません。CTEの名前は別のSQL文からは使えません。
ひよこ ひよこ
CTEは、データベースに新しいテーブルを作るの?
ペンギン先生 ペンギン先生
WITH句で、文の中だけで使える結果に名前を付けるものだよ。たとえばWITH totals AS (...)と定義すれば、後ろのSELECTでtotalsを参照できる。別のSQL文からその名前を使うわけではないんだ。
ひよこ ひよこ
どう役に立つ?
ペンギン先生 ペンギン先生
売上を集計する部分をtotals、そこから条件に合うものを選ぶ部分をselected、というように分けられる。深い入れ子にする代わりに、各部分の役割を名前で示せるよ。ただし名前を増やすだけで読みやすくなるわけではないので、意味のある区切りにしよう。
ひよこ ひよこ
同じCTEを何度も使える?
ペンギン先生 ペンギン先生
同じ文の中で複数回参照できるよ。でも「同じ名前で参照できる」と「必ず1回だけ物理的に計算する」は別の話。データベースやクエリの条件によって、外側のクエリに組み込むか、中間結果を作るかが変わるんだ。
ひよこ ひよこ
再帰CTEは何をするの?
ペンギン先生 ペンギン先生
初期の行から、直前の結果を参照して次の行を求める。組織や部品の親子関係をたどる用途があるよ。PostgreSQLやMySQLではWITH RECURSIVEを使う。循環する関係がある場合には、同じ場所をたどり続けない対策も必要だね。
ひよこ ひよこ
ビューとの違いは?
ペンギン先生 ペンギン先生
ビューは定義をデータベースに保存して、別の文からも使える。CTEの定義はその文の中だけだよ。一時テーブルのように、作成して後の文で操作するものとも違う。どれを使うかは、使う範囲や処理の目的で決めよう。
もっと詳しく知りたい人へ

PostgreSQLではCTEが「最適化の壁」になる?

PostgreSQL 12以降は、非再帰で副作用のないCTEが1回だけ参照される場合などに、外側のクエリへ組み込んで最適化できます。複数回参照される場合などには中間結果を作ることがあり、MATERIALIZED・NOT MATERIALIZEDで指定できる条件もあります。「12以前」ではなく「12より前」と区別し、使用版と実行計画を確認します。

再帰CTEなら木やグラフをそのまま安全に探索できる?

終了条件が必要です。循環があると繰り返しが終わらない場合があります。PostgreSQLのCYCLE句や訪問済みの経路を使う方法などを確認します。行の表示順も自動的に保証されるものではなく、必要な順序を明示します。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「CTE」って出てきたら「SQL文の中で使う結果に名前を付ける仕組み」と思えばだいたいOK!
📖 おまけ:英語の意味
「Common Table Expression」 = 共通テーブル式
💬 1つのSQL文の中で、テーブルのように参照できる式に名前を付けます。CREATE TEMPORARY TABLEで作る一時テーブルとは区別します。

参考資料

← 用語集にもどる