SQL WITH句:共通テーブル式(CTE)と再帰クエリ

Published: 2026-02-04

WITH句(Common Table Expression、CTEとも呼ばれます)は、クエリの中で参照できる一時的な名前付き結果セットを定義できます。これにより、複雑なクエリを読みやすく、再利用しやすくできます。SQLite、PostgreSQL、MySQL 8.0+、SQL Server、Oracle など、ほとんどのモダンなSQLデータベースで利用できます。

サンプルデータ

以下の2つのテーブルを、すべての例で使用します。

employees テーブル:

id name manager_id salary
1 Alice NULL 120000
2 Bob 1 80000
3 Carol 1 85000
4 Dave 2 60000
5 Eve 2 62000
6 Frank 3 58000

sales テーブル:

id employee_id amount month
1 2 5000 January
2 2 6000 February
3 3 7000 January
4 3 8000 February
5 4 3000 January
6 5 4000 January
7 6 2500 February

基本的なWITH句(非再帰)

WITH句は、クエリの実行中だけ存在する、1つ以上の名前付き一時テーブルを定義します。

例:従業員ごとの売上合計

employee_sales CTEで従業員ごとの売上合計を計算し、それを employees テーブルと結合して名前を表示します。

複数のCTE

カンマで区切って複数のCTEを定義できます。後に定義したCTEは、前に定義したCTEを参照できます。

例:複数の指標を使った売上分析

WITH RECURSIVE:階層構造の走査

WITH RECURSIVE を使うと、CTEが自分自身を参照できるようになり、階層構造や木構造のデータをたどることができます。これは、組織図、カテゴリ階層、その他の親子関係を扱うときに便利です。

再帰CTEは2つの部分から成ります。

  1. 基底クエリ: 最初の行集合
  2. 再帰クエリ: 関連する行を見つけるために、CTE自身を参照するクエリ

例:組織図(あるマネージャー配下の全従業員)

CEOである Alice の配下にいるすべての従業員を取得します。

例:指揮系統(マネージャー階層をたどる)

Dave(Bob に報告し、Bob は Alice に報告する)の完全な指揮系統を取得します。

データベースごとの WITH RECURSIVE 構文

WITH RECURSIVE をサポートしているデータベース:

  • SQLite — 3.8.3+ (2013)
  • PostgreSQL — 8.4+ (2009)
  • SQL Server — 2005+(「Recursive CTE」と呼ばれる)
  • Oracle — 11g+(「Recursive Subquery Factoring」と呼ばれる)
  • MySQL — 8.0+ (2018)

注意: 古いバージョンの MySQL やその他一部のデータベースは再帰CTEをサポートしていません。その場合は、ストアドプロシージャやアプリケーション側での再帰処理など、別のアプローチが必要になります。

WITH句の主なユースケース

  • 複雑なクエリの単純化 — 大きなクエリを論理的なステップに分割する
  • サブクエリの再利用 — 計算を一度定義し、複数回利用する
  • 階層構造の走査 — 組織図、カテゴリ、コメントなどの木構造をたどる
  • 連番の生成 — 数値範囲や日付範囲を生成する
  • 段階的な集計 — 結果をステップごとに積み上げていく

まとめ

  • WITH(CTE)は、クエリ内で使用する名前付き一時結果セットを作成する
  • 複数のCTEを連鎖させて定義できる
  • WITH RECURSIVE を使うと、階層クエリのためにCTEが自分自身を参照できる
  • 再帰CTEには、UNION ALL で区切られた基底部と再帰部が必要
  • すべてのモダンなSQLデータベースでサポートされている(細かな構文は多少異なる場合がある)

上の例を少し変えて、さまざまな階層構造や計算パターンを試してみてください。