カテゴリ: データベース 更新日: 2026/04/09

PostgreSQLのWITH句(CTE)を徹底解説!複雑なSQLクエリを初心者でも読みやすく整理する方法

PostgreSQLのCTE(WITH)とは?使いどころを初心者向けに解説
PostgreSQLのCTE(WITH)とは?使いどころを初心者向けに解説

先生と生徒の会話形式で理解しよう

生徒

「先生、SQLで長い命令を書いていると、途中で何をやっているのか分からなくなっちゃいます。もっとスッキリ整理する方法はないですか?」

先生

「それなら『CTE(共通テーブル式)』という機能がぴったりですよ。PostgreSQLでは『WITH句』とも呼ばれます。料理で例えるなら、下ごしらえした食材を一時的にボウルに入れておいて、後でメインの鍋に投入するようなイメージですね。」

生徒

「下ごしらえ…ですか?パソコンに慣れていない私でも、そのボウルを使えば分かりやすくなりますか?」

先生

「もちろんです。一度に全部をやろうとせず、小さなステップに分けることができるので、頭の中が整理されてミスも減りますよ。一緒に見ていきましょう!」

1. SQLとは何か?

1. SQLとは何か?
1. SQLとは何か?

SQL(エスキューエル)は、データベースと呼ばれる「大量のデータを整理して保存する箱」に対して指示を出すための言語です。例えば、会員名簿の中から特定の人を探したり、新しい人を追加したりするときに使います。PostgreSQL(ポストグレスキューエル)は、このSQLを使ってデータを管理するための代表的なシステムの一つです。

通常、データを取得するときは「SELECT(セレクト)」という命令を使いますが、条件が複雑になると、命令文がどんどん長く、複雑になってしまいます。そこで役立つのが、今回解説する「WITH句(CTE)」というテクニックです。

エンジニアの必須スキル「SQL」を、 図解と豊富な練習問題でゼロから体系的に学びたい人へ。 MySQLやPostgreSQLなど、各種データベースに対応した不朽の入門書です。

SQL 第2版 ゼロからはじめるデータベース操作をAmazonで見る

※ Amazon広告リンク

2. CTE(WITH句)とは?「一時的なメモ」の魔法

2. CTE(WITH句)とは?「一時的なメモ」の魔法
2. CTE(WITH句)とは?「一時的なメモ」の魔法

CTEとは「Common Table Expression(コモン・テーブル・エクスプレッション)」の略で、日本語では「共通テーブル式」と呼びます。難しく聞こえますが、要するに「クエリ(命令文)の中でだけ使える、一時的な名前付きの表」のことです。

私たちが複雑な計算をするとき、計算の途中の数字を忘れないようにメモ用紙に書いておきますよね。CTEはそのメモ用紙のような役割を果たします。PostgreSQLで「WITH」という言葉を使って、まず「こういう条件で絞り込んだデータを『作業用メモ』という名前にします」と宣言します。そのあとの本番の命令で、その「作業用メモ」という名前を使ってデータを呼び出せるのです。

これにより、一つの巨大で読みづらい命令を、いくつかの小さな分かりやすいステップに分割できるのが最大のメリットです。プログラミングの経験がなくても、「まずAという作業をして、その結果を使ってBという作業をする」という手順をそのままSQLに書き起こせるようになります。

3. なぜCTEを使うのか?主なメリット

3. なぜCTEを使うのか?主なメリット
3. なぜCTEを使うのか?主なメリット

CTEを使う理由は、主に3つあります。

  • 読みやすくなる(可読性の向上): 命令が上から下に流れるように書けるので、後で見返したときに理解しやすくなります。
  • 再利用ができる: 同じ条件の絞り込みを何度も書く必要がなく、一度CTEとして定義すれば、その後の命令で何度でも使い回せます。
  • 複雑な構造を整理できる: 「サブクエリ」と呼ばれる、命令の中に入れ子状に別の命令を詰め込む手法がありますが、CTEを使えばこの入れ子構造を解消し、平坦に書くことができます。

4. 実践1:特定の条件で絞り込んだリストを使う

4. 実践1:特定の条件で絞り込んだリストを使う
4. 実践1:特定の条件で絞り込んだリストを使う

まずは、簡単な例から見ていきましょう。お店の「商品リスト」から、価格が500円以上の高い商品だけを取り出し、さらにその中から特定のカテゴリの商品を探す、という作業を考えます。

使用する「products(商品)」テーブルは以下の通りです。


id | name       | price | category
---+------------+-------+-----------
1  | リンゴ     | 150   | 果物
2  | メロン     | 1200  | 果物
3  | 牛肉       | 2500  | 肉
4  | 鶏肉       | 450   | 肉
5  | キャベツ   | 200   | 野菜
6  | 高級ブドウ | 3000  | 果物

このデータから、「500円以上の商品」を一度メモ(CTE)にまとめ、そこからさらに「果物」だけを表示するSQLを書きます。


WITH expensive_items AS (
    SELECT *
    FROM products
    WHERE price >= 500
)
SELECT name, price
FROM expensive_items
WHERE category = '果物';

解説:
最初の WITH expensive_items AS (...) の部分で、「500円以上のデータを expensive_items という名前にするよ!」と宣言しています。後半の SELECT 文では、元のテーブルではなく、この expensive_items からデータを取り出しています。

実行結果は以下のようになります。


name       | price
-----------+-------
メロン     | 1200
高級ブドウ | 3000

5. 実践2:複数の「メモ」を組み合わせて使う

5. 実践2:複数の「メモ」を組み合わせて使う
5. 実践2:複数の「メモ」を組み合わせて使う

CTEのすごいところは、メモ(ボウル)を複数作れることです。例えば、「売上データ」と「担当者名簿」という2つの情報をそれぞれ整理してから、最後に合体させるといった使い方ができます。

以下の「sales(売上)」テーブルと「staff(スタッフ)」テーブルを使ってみましょう。


-- salesテーブル
id | staff_id | amount
---+----------+-------
1  | 1        | 5000
2  | 2        | 3000
3  | 1        | 2000
4  | 3        | 8000

-- staffテーブル
id | name
---+--------
1  | 田中
2  | 佐藤
3  | 鈴木

「スタッフごとの売上の合計」をまず計算し、その結果に名前をくっつける処理を書いてみます。


WITH total_sales AS (
    SELECT staff_id, SUM(amount) AS sum_amount
    FROM sales
    GROUP BY staff_id
)
SELECT s.name, t.sum_amount
FROM staff s
JOIN total_sales t ON s.id = t.staff_id
ORDER BY t.sum_amount DESC;

用語解説:
SUM(サム): 合計を出す命令です。
GROUP BY(グループ・バイ): 同じ項目(ここではスタッフID)ごとにデータをまとめる命令です。
JOIN(ジョイン): 2つの異なる表を、共通の項目(IDなど)をヒントにしてくっつける魔法のような命令です。

実行結果は以下のようになります。


name | sum_amount
-----+-----------
鈴木 | 8000
田中 | 7000
佐藤 | 3000

6. 実践3:データの更新(UPDATE)でもWITH句は使える!

6. 実践3:データの更新(UPDATE)でもWITH句は使える!
6. 実践3:データの更新(UPDATE)でもWITH句は使える!

WITH句は、データを見るだけでなく、データを書き換えるときにも便利です。例えば、「特定の成績を超えた生徒にだけ、ボーナスポイントを付与する」といった複雑な更新も、ステップに分ければ安全に行えます。未経験の方にとって、データの書き換えは少し怖いものですが、CTEで「書き換える対象」を明確に定義すればミスを防げます。

次の「students(生徒)」テーブルを見てください。


id | name | score | rank_comment
---+------+-------+--------------
1  | 健太 | 85    | (空)
2  | 美咲 | 92    | (空)
3  | 翔太 | 45    | (空)
4  | 結衣 | 78    | (空)

「80点以上の生徒」をCTEで抽出し、その生徒たちの rank_comment 欄に「優秀」という文字を書き込みます。


WITH high_scorers AS (
    SELECT id
    FROM students
    WHERE score >= 80
)
UPDATE students
SET rank_comment = '優秀'
WHERE id IN (SELECT id FROM high_scorers);

解説:
まず high_scorers というメモに80点以上の生徒のIDを保存します。その後の UPDATE 命令で、「そのメモの中にIDがある人だけ」を対象にコメントを書き換えています。

実行後のテーブルの状態は以下の通りです。


id | name | score | rank_comment
---+------+-------+--------------
1  | 健太 | 85    | 優秀
2  | 美咲 | 92    | 優秀
3  | 翔太 | 45    | (空)
4  | 結衣 | 78    | (空)

7. CTEを使うときの注意点とコツ

7. CTEを使うときの注意点とコツ
7. CTEを使うときの注意点とコツ

非常に便利なCTEですが、いくつか知っておくべきポイントがあります。まず、CTEで作った「一時的な表(メモ)」は、その命令が終わるとすぐに消えてしまいます。ずっと保存されるものではないので、使い捨ての作業用として活用しましょう。また、PostgreSQLの古いバージョンではCTEを使いすぎると処理速度が少し遅くなることがありましたが、最新のバージョンでは非常に賢く処理してくれるので、基本的には積極的に使って大丈夫です。

パソコンの操作に慣れていない間は、一つの大きな表をそのままいじろうとしてパニックになりがちです。しかし、このWITH句を覚えることで、「まずはここだけ見る」「次にここを加工する」という、論理的な思考がそのままSQLとして形になります。これは、正確なデータ分析を行うための第一歩と言えるでしょう。

8. データベース操作を楽しく学ぶために

8. データベース操作を楽しく学ぶために
8. データベース操作を楽しく学ぶために

PostgreSQLの学習において、WITH句(CTE)をマスターすることは、初心者から中級者への大きな壁を乗り越えることと同じです。最初は「WITH」や「AS」といった英語の並びに戸惑うかもしれませんが、意味を理解すればこれほど心強い味方はありません。まるでパズルを組み立てるように、小さなパーツ(CTE)を作って、それを最後に大きな作品(最終的なクエリ結果)にする感覚を楽しんでください。

SQLの世界は、一度基本を覚えると一生使えるスキルになります。名簿の管理、在庫のチェック、売上の分析など、日常生活や事務作業のあらゆる場面で「データを扱う考え方」が役立つはずです。焦らず一歩ずつ、まずはWITH句を使って「読みやすいSQL」を書くことから始めてみましょう。

カテゴリの一覧へ
新着記事
New1
データベース
SQLトランザクションとは?初心者向け完全ガイド!データベースの安全なデータ操作を徹底解説
New2
Ruby
Rubyのハッシュを徹底比較!シンボルキーと文字列キーの違いと使い分け
New3
Rails
Railsマイグレーション入門|rails g migration から db:migrate までを初心者向けに完全解説
New4
Rails
DockerでRailsを動かす完全入門|マルチステージDockerfileとdocker-compose雛形を初心者向けに徹底解説
人気記事
No.1
Java&Spring記事人気No1
Ruby
WindowsでRubyをインストールする方法!RubyInstallerとMSYS2を使った完全ガイド
No.2
Java&Spring記事人気No2
Rails
Railsのimportmap入門|Node不要でJavaScriptを使う方法と落とし穴をやさしく解説
No.3
Java&Spring記事人気No3
Ruby
VS Codeで快適Ruby開発!拡張機能・デバッグ・Lint/Format自動化ガイド
No.4
Java&Spring記事人気No4
データベース
PostgreSQLのCTE(WITH句)完全解説!複雑なSQLを整理して読みやすくする書き方
No.5
Java&Spring記事人気No5
データベース
SQLで複数テーブルを結合する方法を徹底解説!初心者でも図解でわかるJOINと集計の基本
No.6
Java&Spring記事人気No6
データベース
SQL GROUP BYのパフォーマンス改善ガイド!重い処理を高速化する初心者向け対策
No.7
Java&Spring記事人気No7
Rails
Railsのログ設定を完全理解!初心者でもわかる構造化ログ・Request ID・logrageの使い方
No.8
Java&Spring記事人気No8
データベース
PostgreSQL配列型(Array)入門ガイド!初心者でもわかるデータベースの便利な使い方