PostgreSQLのWITH句(CTE)を徹底解説!複雑なSQLクエリを初心者でも読みやすく整理する方法
生徒
「先生、SQLで長い命令を書いていると、途中で何をやっているのか分からなくなっちゃいます。もっとスッキリ整理する方法はないですか?」
先生
「それなら『CTE(共通テーブル式)』という機能がぴったりですよ。PostgreSQLでは『WITH句』とも呼ばれます。料理で例えるなら、下ごしらえした食材を一時的にボウルに入れておいて、後でメインの鍋に投入するようなイメージですね。」
生徒
「下ごしらえ…ですか?パソコンに慣れていない私でも、そのボウルを使えば分かりやすくなりますか?」
先生
「もちろんです。一度に全部をやろうとせず、小さなステップに分けることができるので、頭の中が整理されてミスも減りますよ。一緒に見ていきましょう!」
1. SQLとは何か?
SQL(エスキューエル)は、データベースと呼ばれる「大量のデータを整理して保存する箱」に対して指示を出すための言語です。例えば、会員名簿の中から特定の人を探したり、新しい人を追加したりするときに使います。PostgreSQL(ポストグレスキューエル)は、このSQLを使ってデータを管理するための代表的なシステムの一つです。
通常、データを取得するときは「SELECT(セレクト)」という命令を使いますが、条件が複雑になると、命令文がどんどん長く、複雑になってしまいます。そこで役立つのが、今回解説する「WITH句(CTE)」というテクニックです。
エンジニアの必須スキル「SQL」を、 図解と豊富な練習問題でゼロから体系的に学びたい人へ。 MySQLやPostgreSQLなど、各種データベースに対応した不朽の入門書です。
SQL 第2版 ゼロからはじめるデータベース操作をAmazonで見る※ Amazon広告リンク
2. CTE(WITH句)とは?「一時的なメモ」の魔法
CTEとは「Common Table Expression(コモン・テーブル・エクスプレッション)」の略で、日本語では「共通テーブル式」と呼びます。難しく聞こえますが、要するに「クエリ(命令文)の中でだけ使える、一時的な名前付きの表」のことです。
私たちが複雑な計算をするとき、計算の途中の数字を忘れないようにメモ用紙に書いておきますよね。CTEはそのメモ用紙のような役割を果たします。PostgreSQLで「WITH」という言葉を使って、まず「こういう条件で絞り込んだデータを『作業用メモ』という名前にします」と宣言します。そのあとの本番の命令で、その「作業用メモ」という名前を使ってデータを呼び出せるのです。
これにより、一つの巨大で読みづらい命令を、いくつかの小さな分かりやすいステップに分割できるのが最大のメリットです。プログラミングの経験がなくても、「まずAという作業をして、その結果を使ってBという作業をする」という手順をそのままSQLに書き起こせるようになります。
3. なぜCTEを使うのか?主なメリット
CTEを使う理由は、主に3つあります。
- 読みやすくなる(可読性の向上): 命令が上から下に流れるように書けるので、後で見返したときに理解しやすくなります。
- 再利用ができる: 同じ条件の絞り込みを何度も書く必要がなく、一度CTEとして定義すれば、その後の命令で何度でも使い回せます。
- 複雑な構造を整理できる: 「サブクエリ」と呼ばれる、命令の中に入れ子状に別の命令を詰め込む手法がありますが、CTEを使えばこの入れ子構造を解消し、平坦に書くことができます。
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:複数の「メモ」を組み合わせて使う
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句は使える!
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を使うときの注意点とコツ
非常に便利なCTEですが、いくつか知っておくべきポイントがあります。まず、CTEで作った「一時的な表(メモ)」は、その命令が終わるとすぐに消えてしまいます。ずっと保存されるものではないので、使い捨ての作業用として活用しましょう。また、PostgreSQLの古いバージョンではCTEを使いすぎると処理速度が少し遅くなることがありましたが、最新のバージョンでは非常に賢く処理してくれるので、基本的には積極的に使って大丈夫です。
パソコンの操作に慣れていない間は、一つの大きな表をそのままいじろうとしてパニックになりがちです。しかし、このWITH句を覚えることで、「まずはここだけ見る」「次にここを加工する」という、論理的な思考がそのままSQLとして形になります。これは、正確なデータ分析を行うための第一歩と言えるでしょう。
8. データベース操作を楽しく学ぶために
PostgreSQLの学習において、WITH句(CTE)をマスターすることは、初心者から中級者への大きな壁を乗り越えることと同じです。最初は「WITH」や「AS」といった英語の並びに戸惑うかもしれませんが、意味を理解すればこれほど心強い味方はありません。まるでパズルを組み立てるように、小さなパーツ(CTE)を作って、それを最後に大きな作品(最終的なクエリ結果)にする感覚を楽しんでください。
SQLの世界は、一度基本を覚えると一生使えるスキルになります。名簿の管理、在庫のチェック、売上の分析など、日常生活や事務作業のあらゆる場面で「データを扱う考え方」が役立つはずです。焦らず一歩ずつ、まずはWITH句を使って「読みやすいSQL」を書くことから始めてみましょう。