サブクエリとCTE: SQLを読みやすく分ける
Stage 4 — 第1章 | データ分析基礎カリキュラム 推定学習時間:30〜40分 | 難易度:★★★☆☆
この章で学ぶこと
分析SQLは、条件で絞る、集計する、別の表と結合する、さらに計算する、という処理が重なって長くなりがちです。 長いSQLを一気に書くと、どこで何をしているのか分かりにくくなります。
この章では、SQLを段階に分けて読みやすくする サブクエリ と CTE を学びます。
この章を終えると、こんなことができるようになります:
- サブクエリで集計結果を次の処理に使える
- CTEを使ってSQLを手順ごとに分けられる
- 複雑な分析SQLを読みやすく整理できる
- 実務でSQLを共有するときの見通しをよくできる
1. 分析SQLは段階に分けると読みやすい
たとえば「顧客ごとの累計購入金額を出し、10,000円以上の顧客だけを見る」という分析を考えます。 必要な処理は、次のように分けられます。
| 手順 | 内容 |
|---|---|
| 1 | 完了注文だけに絞る |
| 2 | 顧客ごとに売上を合計する |
| 3 | 合計売上が10,000円以上の顧客だけ残す |
一つひとつは難しくありません。 しかし、すべてを一文に詰め込むと読みにくくなります。
分析SQLでは、「処理の手順を見える形にする」ことが大切です。
2. サブクエリで集計結果を使う
サブクエリは、SQLの中に書く別のSQLです。 次の例では、まず顧客ごとの売上を集計し、その結果から条件に合う顧客を取り出します。
SELECT
customer_id,
total_sales
FROM (
SELECT
customer_id,
SUM(total_amount) AS total_sales
FROM orders
WHERE status = 'completed'
GROUP BY customer_id
) AS customer_sales
WHERE total_sales >= 10000;
内側のSQLが customer_sales という一時的な表のように扱われます。
外側のSQLでは、その結果に対して WHERE total_sales >= 10000 を指定しています。
サブクエリは便利ですが、処理が増えると括弧の範囲が見えにくくなることがあります。
3. CTEで手順に名前をつける
CTEは、WITH 句を使ってSQLの途中結果に名前をつける書き方です。
先ほどの例をCTEで書くと、次のようになります。
WITH customer_sales AS (
SELECT
customer_id,
SUM(total_amount) AS total_sales
FROM orders
WHERE status = 'completed'
GROUP BY customer_id
)
SELECT
customer_id,
total_sales
FROM customer_sales
WHERE total_sales >= 10000;
customer_sales という名前を見るだけで、「顧客別売上を作っている」と分かります。
実務では、サブクエリよりCTEのほうが読みやすい場面が多くあります。
4. 複数のCTEで分析の流れを作る
CTEは複数並べることもできます。 次の例では、完了注文を取り出してから、顧客別に集計し、最後に顧客情報を結合します。
WITH completed_orders AS (
SELECT
order_id,
customer_id,
order_date,
total_amount
FROM orders
WHERE status = 'completed'
),
customer_sales AS (
SELECT
customer_id,
COUNT(*) AS order_count,
SUM(total_amount) AS total_sales
FROM completed_orders
GROUP BY customer_id
)
SELECT
c.customer_id,
c.customer_name,
c.prefecture,
s.order_count,
s.total_sales
FROM customer_sales AS s
JOIN customers AS c
ON s.customer_id = c.customer_id
ORDER BY s.total_sales DESC;
このSQLは少し長いですが、処理の流れは追いやすくなっています。
completed_orders: 分析対象の注文を作るcustomer_sales: 顧客ごとの指標を作る- 最後の
SELECT: 顧客名や都道府県を付けて表示する
CTE名は、処理の意味が分かる名前にしましょう。
5. CTEを書くときの注意点
CTEは便利ですが、何でも細かく分ければよいわけではありません。 読みやすさを上げるために使います。
| 書き方 | よい使いどころ |
|---|---|
| サブクエリ | 短く、1回だけ使う中間結果 |
| CTE | 手順を分けたい、名前をつけたい中間結果 |
| テーブル化 | 何度も使う、チームで共有する分析用データ |
CTEを使うときは、各CTEが「何を表す表なのか」を説明できるようにします。
tmp1, tmp2 のような名前は避け、completed_orders, customer_sales のように意味が伝わる名前にしましょう。
実務での使いどころ: 分析手順に名前をつける
CTEは、複雑な分析SQLを読みやすくするための道具です。 実務では、最終結果だけでなく「どの手順でその結果を作ったか」が重要になります。
WITH completed_orders AS (
SELECT
order_id,
customer_id,
total_amount
FROM orders
WHERE status = 'completed'
),
customer_sales AS (
SELECT
customer_id,
SUM(total_amount) AS sales
FROM completed_orders
GROUP BY customer_id
)
SELECT *
FROM customer_sales;
このSQLでは、完了注文を作る手順と、顧客別に集計する手順を分けています。 CTE名を見るだけで、分析の流れが分かります。
| CTE名 | 役割 |
|---|---|
completed_orders |
対象注文を定義する |
customer_sales |
顧客別売上を作る |
monthly_sales |
月別売上を作る |
ranked_products |
ランキング用の結果を作る |
CTEは長いSQLを短くするものではなく、分析の手順を読みやすくするものです。
ミニ演習
次の分析をCTEに分けるなら、どんな名前をつけるか考えてください。
- 完了注文だけを抽出するCTE。
- 顧客別売上を作るCTE。
- 月別売上を作るCTE。
- CTEを使うとレビューしやすくなる理由を説明する。
まとめ
| 構文 | 意味 | 例 |
|---|---|---|
| サブクエリ | SQLの中に書くSQL | FROM (SELECT ...) AS t |
| CTE | 中間結果に名前をつける | WITH customer_sales AS (...) |
WITH |
CTEを定義する句 | WITH completed_orders AS (...) |
この章のキーメッセージ: 分析SQLは、正しく動くだけでなく、後から読めることも重要です。サブクエリやCTEを使い、処理を意味のある単位に分けましょう。
この章の確認
- サブクエリはどのような場面で使いますか?
- CTEを使うと、SQLの読みやすさはどのように改善されますか?
- 完了注文だけを取り出すCTE
completed_ordersを書いてください。 - CTE名をつけるときに避けたい名前の例を説明してください。