🔍 Step 2: サブクエリの基礎
クエリの中にクエリを入れて、複雑な条件を簡単に表現しよう!
- サブクエリとは何か、なぜ便利なのか
- WHERE句でのサブクエリの使い方
- 単一行サブクエリと複数行サブクエリの違い
- IN演算子、EXISTS演算子との組み合わせ
- 実践的なサブクエリのパターン
🎯 1. サブクエリとは何か?
1-1. サブクエリの基本概念
サブクエリ(副問い合わせ)とは、SQLクエリの中に別のSQLクエリを入れる技術です。
日常生活で例えると、「今月の平均気温より暑い日を教えて」と聞くようなものです。この質問に答えるには、まず「今月の平均気温」を計算してから、それより暑い日を探しますよね。サブクエリを使えば、この2つのステップを1つのクエリで実現できます。
サブクエリは「箱の中に箱を入れる」ようなものです。外側の箱(メインクエリ)の中に、内側の箱(サブクエリ)があり、内側の箱の中身が先に確認されてから、外側の箱が処理されます。
1-2. サブクエリを使わない場合と使う場合の比較
「平均価格より高い商品を探したい」という場合を考えてみましょう。
■ サブクエリを使わない場合(2ステップ必要)
まず、平均価格を調べるクエリを実行します。
※横にスクロールできます
次に、その結果(1500円)を手動で使って、検索クエリを実行します。
※横にスクロールできます
この方法だと、2回クエリを実行する必要があり、平均価格が変わるたびに手動で値を変更しなければなりません。
■ サブクエリを使う場合(1ステップで完了!)
サブクエリを使えば、1つのクエリで同じことができます。
※横にスクロールできます
SELECT * FROM products→ productsテーブルから全ての列を取得WHERE price >→ 価格が〜より大きいという条件(SELECT AVG(price) FROM products)→ これがサブクエリ!productsテーブルの平均価格を計算して返す
- まず括弧内のサブクエリ
SELECT AVG(price) FROM productsが実行される - サブクエリの結果(例: 1500)がメインクエリに渡される
- メインクエリが
WHERE price > 1500として実行される
1-3. サブクエリのメリット
- 1つのクエリで完結できる:複数回のクエリ実行が不要
- 動的な値が使える:データが変わっても自動的に最新の値で計算される
- 複雑な条件を簡潔に表現できる:「平均より上」「最大値と同じ」などの条件が書きやすい
- コードの可読性が向上:何をしたいかが1つのクエリで分かる
1-4. サブクエリが使える3つの場所
サブクエリは、SQLの中の様々な場所で使うことができます。このコースでは主に3つの場所を学びます。
| 場所 | 用途 | 学ぶステップ |
|---|---|---|
| WHERE句 | 条件の中で使う(最も一般的) | このステップ(Step 2) |
| FROM句 | テーブルの代わりに使う | Step 3 |
| SELECT句 | 列の値として使う | Step 5 |
📊 2. WHERE句でのサブクエリ
2-1. 基本的な使い方
WHERE句の条件部分でサブクエリを使うのが、最も基本的で一般的なパターンです。「〜より大きい」「〜と等しい」「〜に含まれる」といった条件の「〜」の部分をサブクエリで動的に計算できます。
※横にスクロールできます
2-2. 例1:平均価格より高い商品を取得する
最も基本的な例として、平均価格より高い商品を取得してみましょう。
やりたいこと:productsテーブルから、全商品の平均価格より高い価格の商品を探す
※横にスクロールできます
SELECT product_name, price, category→ 商品名、価格、カテゴリを取得FROM products→ productsテーブルからWHERE price >→ 価格が〜より大きいという条件(SELECT AVG(price) FROM products)→ 全商品の平均価格を計算するサブクエリ
| product_name | price | category |
|---|---|---|
| 高級ヘッドホン | 25,000 | 家電 |
| プレミアムコーヒー | 3,200 | 食品 |
| デザイナーズチェア | 45,000 | 家具 |
※ 平均価格が1,500円の場合、1,500円より高い商品が表示される
2-3. 例2:最高価格の商品を取得する
最も高い価格の商品を取得したい場合、MAX関数とサブクエリを組み合わせます。
やりたいこと:productsテーブルから、最も高い価格の商品を探す
※横にスクロールできます
WHERE price =→ 価格が〜と等しいという条件(>ではなく=)(SELECT MAX(price) FROM products)→ 最高価格を計算するサブクエリ
最高価格「より高い」商品は存在しないので、最高価格「と等しい」商品を探します。
2-4. 例3:特定カテゴリの平均価格より高い商品
「家電」カテゴリの平均価格を基準にして、それより高い全カテゴリの商品を探してみましょう。
やりたいこと:「家電」カテゴリの平均価格より高い商品を、全カテゴリから探す
※横にスクロールできます
- サブクエリ内の
WHERE category = '家電'→ 家電カテゴリだけを対象に平均を計算 - メインクエリには
WHERE category = '家電'がない → 全カテゴリが検索対象
サブクエリとメインクエリは独立しています。サブクエリで「家電」に絞っても、メインクエリは全商品を検索します。
2-5. 例4:特定の顧客より多く購入している顧客を探す
「顧客ID 1001さんの購入金額より多く買っている顧客は誰か?」を調べてみましょう。
やりたいこと:顧客ID 1001の総購入額より多く購入している顧客を探す
※横にスクロールできます
- サブクエリ: 顧客ID 1001の
total_amount(総購入額)を取得 - メインクエリ: その金額より大きい
total_amountを持つ顧客を検索
2-6. 例5:日付に関する比較
最新の注文日より前の注文を取得してみましょう。これは「最後の1件以外を取得する」という意味になります。
やりたいこと:最新の注文日より前(古い)の注文を取得する
※横にスクロールできます
(SELECT MAX(order_date) FROM orders)→ 最新の注文日を取得WHERE order_date <→ その日付より前(小さい = 古い)
- サブクエリが最初に実行される(括弧の中)
- サブクエリの結果が1つの値として確定する
- その値を使ってメインクエリが実行される
この順序を理解しておくと、サブクエリの動作が分かりやすくなります!
🔢 3. 単一行サブクエリ
3-1. 単一行サブクエリとは
単一行サブクエリとは、1つの値だけを返すサブクエリのことです。「平均価格」「最高価格」「件数」など、計算結果が1つの数値や文字列になるものが該当します。
この種類のサブクエリは、比較演算子(=, >, <, >=, <=, <>)と一緒に使います。
| 関数 | 意味 | 返す値の例 |
|---|---|---|
AVG() |
平均値 | 1500.00 |
SUM() |
合計 | 1250000 |
MAX() |
最大値 | 50000 |
MIN() |
最小値 | 100 |
COUNT() |
件数 | 500 |
3-2. 例1:平均より高い商品(詳細解説)
単一行サブクエリの最も基本的な例を、もう少し詳しく見てみましょう。
やりたいこと:平均価格より高い商品を取得する
まず、サブクエリ部分だけを確認します。
※横にスクロールできます
このサブクエリは「1500」という1つの値を返します。これが「単一行サブクエリ」です。
次に、完成形のクエリを見てみましょう。
※横にスクロールできます
(SELECT AVG(price) FROM products)が実行され、結果「1500」が得られる- クエリは
WHERE price > 1500と同じ意味になる - 価格が1500より大きい商品が取得される
3-3. 例2:最安値の2倍以上の商品
サブクエリの結果に計算を加えることもできます。
やりたいこと:最安値の2倍以上の価格の商品を取得する
※横にスクロールできます
(SELECT MIN(price) FROM products)→ 最安値を取得(例: 500円)* 2→ サブクエリの結果に2を掛ける(例: 1000円)WHERE price >= ... * 2→ 最安値の2倍以上(1000円以上)の商品を取得
サブクエリの結果は数値なので、通常の数値と同じように四則演算ができます。
3-4. 例3:全体の売上に対する割合を計算
SELECT句の中でもサブクエリを使うことで、各注文が全体の何%を占めるかを計算できます。
やりたいこと:全体の売上の10%以上を占める大口注文を探す
まず、何をしたいかを分解して考えましょう。
Step 1: 全体の売上合計を取得する
※横にスクロールできます
Step 2: 各注文の割合を計算する式を考える
※横にスクロールできます
Step 3: 完成形のクエリ
※横にスクロールできます
total_amount * 100.0 / (サブクエリ)→ 各注文が全体の何%かを計算ROUND(..., 2)→ 小数点以下2桁に丸める(SELECT SUM(total_amount) FROM orders) * 0.1→ 全体の10%の金額WHERE total_amount >=→ その10%以上の注文だけを取得
3-5. 例4:特定の顧客と同じ都道府県に住む顧客
数値だけでなく、文字列を返すサブクエリも作れます。
やりたいこと:顧客ID 1005と同じ都道府県に住む顧客を探す
※横にスクロールできます
- サブクエリ: 顧客ID 1005の
prefecture(都道府県)を取得(例: '東京都') - メインクエリ:
prefecture = '東京都'の顧客を検索
customer_id = 1005 という条件で、1人の顧客だけが特定されるため、サブクエリは1つの値(都道府県名)だけを返します。
3-6. 単一行サブクエリの注意点:エラーになるケース
比較演算子(=, >, <など)を使う場合、サブクエリは必ず1つの値を返す必要があります。複数の値を返すとエラーになります。
※横にスクロールできます
「家電」カテゴリには複数の商品があります。例えば、テレビ(50,000円)、冷蔵庫(80,000円)、掃除機(30,000円)など。サブクエリが3つの価格を返すため、「price = 50000, 80000, 30000」という意味になり、SQLは処理できません。
- 集計関数(AVG、MAXなど)を使って1つの値にする
- または、IN演算子を使う(次のセクションで説明)
📋 4. 複数行サブクエリとIN演算子
4-1. 複数行サブクエリとは
複数行サブクエリとは、複数の値(行)を返すサブクエリのことです。「注文された商品のID一覧」「東京都の顧客ID一覧」など、リスト形式の結果が該当します。
複数行サブクエリは、比較演算子ではなくIN演算子と一緒に使います。
4-2. IN演算子の復習
まず、IN演算子の基本を復習しましょう。IN演算子は「〜のどれかに一致する」という条件を表します。
※横にスクロールできます
WHERE category IN ('家電', '食品', '本')- → categoryが「家電」「食品」「本」のいずれかに一致する商品を取得
- これは
WHERE category = '家電' OR category = '食品' OR category = '本'と同じ意味
4-3. IN演算子とサブクエリの組み合わせ
IN演算子の括弧の中に、値を直接書く代わりにサブクエリを書くことができます。
やりたいこと:実際に注文されたことがある商品だけを取得する
まず、注文された商品のIDを取得するサブクエリを作ります。
※横にスクロールできます
次に、このサブクエリをIN演算子と組み合わせます。
※横にスクロールできます
SELECT DISTINCT product_id FROM order_details→ 注文された商品IDのリストを取得DISTINCT→ 重複を除去(同じ商品が複数回注文されていても1回だけカウント)WHERE product_id IN (サブクエリ)→ そのリストに含まれる商品IDを持つ商品を取得
| product_id | product_name | price |
|---|---|---|
| 101 | ワイヤレスマウス | 2,500 |
| 105 | USBケーブル | 800 |
| 203 | コーヒー豆 | 1,200 |
4-4. 例2:東京都の顧客が購入した商品(入れ子サブクエリ)
サブクエリの中にさらにサブクエリを入れる「入れ子(ネスト)」も可能です。複雑な条件を段階的に絞り込むことができます。
やりたいこと:東京都に住む顧客が購入した商品を取得する
これを実現するには、以下の3段階で考えます。
Step 1: 東京都の顧客IDを取得する
※横にスクロールできます
Step 2: その顧客の注文IDを取得する
※横にスクロールできます
Step 3: その注文に含まれる商品IDを取得する
※横にスクロールできます
完成形: 商品の詳細情報を取得する
※横にスクロールできます
- 最も内側のサブクエリから実行される(東京都の顧客ID)
- その結果を使って次のサブクエリが実行される(注文ID)
- さらにその結果を使って次のサブクエリが実行される(商品ID)
- 最後にメインクエリが実行される(商品の詳細)
4-5. NOT INで除外する
NOT INを使うと、「含まれない」条件を指定できます。
やりたいこと:一度も注文されていない商品を取得する
※横にスクロールできます
NOT IN→ リストに含まれないものを取得- サブクエリ: 注文されたことがある商品IDのリスト
- 結果: そのリストに含まれない商品 = 一度も注文されていない商品
| 演算子 | 意味 | 使用例 |
|---|---|---|
IN |
リストに含まれるものを取得 | 注文された商品を探す |
NOT IN |
リストに含まれないものを取得 | 注文されていない商品を探す |
4-6. 例5:売れ筋商品で在庫が少ないものを探す
サブクエリと通常の条件を組み合わせることで、より複雑な条件を表現できます。
やりたいこと:10回以上注文された商品で、かつ在庫が50個未満の商品を探す
まず、売れ筋商品(10回以上注文された商品)を取得するサブクエリを作ります。
※横にスクロールできます
次に、完成形のクエリを作ります。
※横にスクロールできます
GROUP BY product_id→ 商品ごとにグループ化HAVING COUNT(*) >= 10→ 注文回数が10回以上のグループだけを残すAND stock < 50→ さらに在庫が50個未満という条件を追加
このようなクエリは「補充が必要な人気商品」を見つけるのに役立ちます。売れているのに在庫が少ない商品は、早急に発注する必要がありますね!
✅ 5. EXISTS演算子との組み合わせ
5-1. EXISTS演算子とは
EXISTSは、サブクエリの結果が存在するかどうかをチェックする演算子です。INとは考え方が少し異なります。
日常生活で例えると、INは「この人は名簿に載っていますか?」と名簿をチェックするイメージ。EXISTSは「この人は何か注文したことがありますか?」と履歴があるかどうかをチェックするイメージです。
- TRUE/FALSEを返す(データの値ではない)
- 結果が1件でもあればTRUE(全件調べる必要がない)
- 大量データの場合、パフォーマンスが良いことが多い
- 相関サブクエリとして使うことが多い
5-2. 相関サブクエリとは
EXISTSを理解する前に、「相関サブクエリ」という概念を知っておきましょう。
これまで見てきたサブクエリは、メインクエリとは独立して実行できました。しかし相関サブクエリは、メインクエリの各行を参照しながら実行されます。
| 種類 | 特徴 | 例 |
|---|---|---|
| 通常のサブクエリ | サブクエリ単体で実行できる | SELECT AVG(price) FROM products |
| 相関サブクエリ | メインクエリの値を参照する | WHERE orders.customer_id = customers.customer_id |
5-3. EXISTSの基本的な使い方
やりたいこと:注文履歴がある顧客を取得する
まず、INを使った書き方を見てみましょう。
※横にスクロールできます
同じことをEXISTSで書くとこうなります。
※横にスクロールできます
SELECT 1→ 「何か1つの値」を返すという意味。EXISTSは値の中身を見ないので、1でも*でも何でもOKWHERE orders.customer_id = customers.customer_id→ 相関サブクエリ!メインクエリのcustomersテーブルの各行を参照しているEXISTS (...)→ サブクエリの結果が1行でもあればTRUE
- customersテーブルの1行目(顧客ID: 1001)を見る
- 「ordersテーブルにcustomer_id = 1001の注文はあるか?」を確認
- あればTRUE → この顧客を結果に含める
- customersテーブルの2行目(顧客ID: 1002)を見る
- 同様に繰り返す...
つまり、メインクエリの各行に対して、サブクエリが実行されるイメージです。
5-4. NOT EXISTSで「存在しない」をチェック
やりたいこと:一度も注文していない顧客を取得する
※横にスクロールできます
NOT EXISTS→ サブクエリの結果が存在しない場合にTRUE- 「この顧客IDの注文が1件もない」という条件
一度も注文していない顧客に対して、初回購入キャンペーンのメールを送りたい場合などに使えます。
5-5. 複数の条件を含むEXISTS
やりたいこと:2024年に1万円以上の注文をした顧客を取得する
※横にスクロールできます
- サブクエリの中に複数の条件(
AND)を追加できる order_date >= '2024-01-01'→ 2024年以降の注文total_amount >= 10000→ 1万円以上の注文- これらすべての条件を満たす注文が存在する顧客だけを取得
5-6. INとEXISTSの違い
INとEXISTSは、多くの場合同じ結果を返しますが、使い方や性能に違いがあります。
| 項目 | IN | EXISTS |
|---|---|---|
| 動作の仕組み | 値のリストを作って比較 | 存在するかどうかをチェック |
| サブクエリの種類 | 通常のサブクエリ | 相関サブクエリ |
| NULLの扱い | NULLがあると予期せぬ結果になる場合がある | NULLに強い |
| パフォーマンス | サブクエリの結果が少ない場合に有利 | サブクエリの結果が多い場合に有利 |
| 読みやすさ | シンプルで直感的 | 少し複雑だが表現力が高い |
- IN: シンプルで読みやすい。初心者はまずINから使ってOK
- EXISTS: 大量データで高速。複雑な条件を書きたいとき
- どちらでも動く場合は、読みやすい方を選びましょう!
- パフォーマンスが気になる場合は、両方試して速い方を使う
🎨 6. 実践的なサブクエリのパターン
ここでは、実務でよく使われるサブクエリのパターンを紹介します。これらのパターンを覚えておくと、様々な場面で応用できます。
6-1. パターン1:トップN件を除外する
やりたいこと:価格トップ10の商品を除いた残りの商品を取得する
- 高級品を除いた「お手頃価格の商品」リストを作りたい
- 上位の外れ値を除いて分析したい
※横にスクロールできます
- サブクエリ:
ORDER BY price DESC LIMIT 10で価格トップ10の商品IDを取得 - メインクエリ:
NOT INでそれらを除外した商品を取得
6-2. パターン2:同じカテゴリ内での比較
やりたいこと:各カテゴリの平均価格より高い商品を取得する
- カテゴリ内で「高価格帯」の商品を特定したい
- 各グループの中で突出したデータを見つけたい
これは相関サブクエリを使います。メインクエリの各商品について、その商品と同じカテゴリの平均価格を計算します。
※横にスクロールできます
products p1とproducts p2→ 同じテーブルに別名をつけて区別WHERE p2.category = p1.category→ メインクエリの商品と同じカテゴリだけを対象に平均を計算- 商品ごとに「自分のカテゴリの平均」と比較している
「家電」カテゴリの平均が20,000円、「食品」カテゴリの平均が500円の場合、家電は20,000円以上、食品は500円以上のものがそれぞれ抽出されます。
6-3. パターン3:複数の集計値を条件に使う
やりたいこと:平均より高く、かつ最高価格の50%以下の商品(中価格帯)を取得する
- 「ちょうどいい価格帯」の商品を探したい
- 極端な値を除いた中間層を分析したい
※横にスクロールできます
price > (SELECT AVG(price) FROM products)→ 平均より高いprice <= (SELECT MAX(price) FROM products) * 0.5→ 最高価格の半分以下- 2つの条件を
ANDで組み合わせ
6-4. パターン4:期間による絞り込み
やりたいこと:直近30日間に注文があった商品を取得する
- 最近売れている商品を把握したい
- 季節商品の動向を確認したい
※横にスクロールできます
DATE('now', '-30 days')→ SQLiteで「今日から30日前」を計算(MySQLではDATE_SUB(NOW(), INTERVAL 30 DAY))- 内側から外側に向かって、「30日以内の注文」→「その注文に含まれる商品」→「商品の詳細」と辿る
6-5. パターン5:OR条件での組み合わせ
やりたいこと:高評価(4.5以上)または売れ筋(20回以上注文)の商品を取得する
- 「おすすめ商品」リストを作りたい
- 複数の基準のどれかを満たすものを探したい
※横にスクロールできます
- 2つのサブクエリを
ORで結合 - 「高評価」または「売れ筋」のどちらかに該当すれば取得される
- 両方に該当する商品は重複せず1回だけ表示される
| パターン | 使う演算子 | 主な用途 |
|---|---|---|
| 平均との比較 | >, < |
平均より上/下のデータを探す |
| 最大/最小との比較 | =, >= |
極端な値を持つデータを探す |
| リストとの照合 | IN |
関連するデータを探す |
| 除外 | NOT IN |
特定のデータを除く |
| 存在確認 | EXISTS |
関連データがあるか確認 |
| 不存在確認 | NOT EXISTS |
関連データがないものを探す |
📝 練習問題
サブクエリを使って、実際に手を動かして確認しましょう!
問題 1基本
平均価格より安い商品
productsテーブルから、平均価格より安い商品の名前と価格を取得してください。
※横にスクロールできます
解説:
- サブクエリ
(SELECT AVG(price) FROM products)で平均価格を計算 WHERE price <で平均より小さい(安い)商品を取得
問題 2基本
最高価格の商品
productsテーブルから、最も高い価格の商品を取得してください。
※横にスクロールできます
解説:
- サブクエリ
(SELECT MAX(price) FROM products)で最高価格を取得 WHERE price =でその価格と等しい商品を取得- 同じ最高価格の商品が複数あれば、すべて表示される
問題 3基本
注文された商品
productsテーブルから、実際に注文されたことがある商品(order_detailsに存在する)を取得してください。
※横にスクロールできます
解説:
- サブクエリで注文された商品IDのリストを取得
DISTINCTで重複を除去(同じ商品が複数回注文されていても1回だけ)IN演算子でリストに含まれる商品を取得
問題 4応用
一度も注文されていない商品
一度も注文されていない商品を取得してください。
※横にスクロールできます
解説:
NOT INを使って、リストに含まれない商品を取得- 注文されたことがある商品IDのリストに含まれない = 一度も注文されていない
問題 5応用
カテゴリ別の平均より高い
「家電」カテゴリの平均価格より高い、すべてのカテゴリの商品を取得してください。
※横にスクロールできます
解説:
- サブクエリで「家電」カテゴリの平均価格を計算
- メインクエリには
WHERE category = '家電'がないので、全カテゴリが対象 - 家電以外のカテゴリでも、家電の平均より高ければ取得される
問題 6応用
注文履歴がある顧客(EXISTS版)
EXISTSを使って、注文履歴がある顧客を取得してください。
※横にスクロールできます
解説:
EXISTSは存在するかどうかをチェックSELECT 1は「何か値を返す」という意味(1でなくても*でもOK)orders.customer_id = customers.customer_idで相関サブクエリを実現
問題 7応用
東京都の顧客が購入した商品
東京都に住む顧客が購入したことがある商品を取得してください。
※横にスクロールできます
解説:
- サブクエリを入れ子(ネスト)にして、段階的に絞り込む
- 最も内側: 東京都の顧客ID → その顧客の注文ID → 注文された商品ID
- 最終的にその商品IDを持つ商品の詳細を取得
問題 8チャレンジ
高額注文をした顧客
全注文の平均金額より高い注文をしたことがある顧客を取得してください。
※横にスクロールできます
解説:
- 最も内側のサブクエリ: 全注文の平均金額を計算
- 中間のサブクエリ: 平均より高い注文をした顧客IDを取得
- メインクエリ: その顧客の詳細情報を取得
DISTINCTで同じ顧客が複数回表示されるのを防ぐ
問題 9チャレンジ
リピーターが購入している商品
3回以上注文をしている顧客(リピーター)が購入している商品を取得してください。
※横にスクロールできます
解説:
- 最も内側:
GROUP BYとHAVINGで3回以上注文した顧客を特定 - その顧客の注文 → 注文された商品 → 商品詳細、と辿る
- リピーターが好む商品を分析するのに使える
問題 10チャレンジ
売れ筋かつ在庫少
10回以上注文されている商品で、かつ在庫が30個未満の商品を取得してください。
※横にスクロールできます
解説:
- サブクエリ: 10回以上注文された商品IDを取得
- メインクエリ: 在庫30未満 AND 売れ筋リストに含まれる
- 補充が必要な人気商品を特定するのに使える
問題 11チャレンジ
一度も注文していない顧客(NOT EXISTS版)
NOT EXISTSを使って、一度も注文していない顧客を取得してください。
※横にスクロールできます
解説:
NOT EXISTSは「存在しない」をチェック- その顧客IDの注文が1件も存在しない顧客を取得
- 初回購入キャンペーンの対象者を探すのに使える
問題 12チャレンジ
複合条件
平均価格より高く、かつ実際に注文されたことがあり、在庫が50個以上ある商品を取得してください。
※横にスクロールできます
解説:
- 3つの条件を
ANDで組み合わせ - 条件1: 平均価格より高い(単一行サブクエリ)
- 条件2: 在庫50個以上(通常の条件)
- 条件3: 注文されたことがある(複数行サブクエリ + IN)
📝 Step 2 のまとめ
- サブクエリは、クエリの中にクエリを入れる技術
- WHERE句でサブクエリを使って、動的な条件を指定できる
- 単一行サブクエリは1つの値を返す(
=,>,<で比較) - 複数行サブクエリは複数の値を返す(
IN,NOT INで使用) - EXISTSで存在するかどうかをチェックできる
- サブクエリを入れ子(ネスト)にして複雑な条件を表現できる
※横にスクロールできます
- 平均との比較: 平均より上/下のデータを探す
- 存在チェック: 関連データがあるかを確認
- 除外処理: NOT INやNOT EXISTSで特定のデータを除く
- 動的な条件: データに応じて条件を変える
- 複数テーブルの連携: JOINを使わずに関連データを取得
- 比較演算子(
=,>,<)は単一行サブクエリで使う - 複数行を返す場合はIN演算子を使う(そうしないとエラー)
- サブクエリの入れ子は3段階までを目安に(読みやすさ優先)
- 大量データではパフォーマンスに注意(JOINやEXISTSを検討)
❓ よくある質問
Q1: サブクエリとJOINはどちらを使うべきですか?
どちらでも書ける場合が多いです!一般的な使い分けの目安:
- 複数の列が必要な場合 → JOIN
- 存在チェックだけの場合 → サブクエリ(EXISTS)
- 値の比較をしたい場合 → サブクエリ
- 迷ったら読みやすい方を選びましょう!
Q2: INとEXISTSの違いは何ですか?
INは値のリストをチェックし、EXISTSは存在をチェックします。
- INは「このリストに含まれていますか?」
- EXISTSは「関連するデータがありますか?」
- 大量データの場合、EXISTSの方が高速なことが多い
- ただし、多くの場合は結果は同じになります
Q3: 「サブクエリが複数行を返す」エラーが出ます
比較演算子(=, >, <)を使っている場合、サブクエリは必ず1つの値を返す必要があります。
解決方法:
- IN演算子に変更する
- 集計関数(AVG、MAXなど)を使って1つの値にする
LIMIT 1を追加して1行だけ取得する
Q4: サブクエリの中でさらにサブクエリを使えますか?
はい、入れ子(ネスト)にできます!ただし、深くなりすぎると読みにくくなるので、3段階までを目安にしましょう。それ以上複雑になる場合は、WITH句(後のステップで学習)やJOINを検討してください。
Q5: サブクエリは遅いと聞きましたが...
必ずしも遅くありません!
- 適切に使えば高速に動作します
- ただし、大量データで複雑な入れ子になると遅くなる場合があります
- 遅い場合は、JOINやウィンドウ関数(後のステップで学習)を検討しましょう
- 実際に両方試して、速い方を使うのがベストです
Q6: DISTINCTはいつ使うべきですか?
INでサブクエリを使う場合、重複を削除するためにDISTINCTを使うことが多いです。
- 同じ商品が複数回注文されていても、商品IDは1回だけあればOK
- DISTINCTを入れると、サブクエリの結果が小さくなり、処理が速くなることも
- EXISTSの場合は不要(存在チェックのため)
Step 3: FROM句のサブクエリでは、サブクエリをテーブルのように使う「派生テーブル」を学びます。集計結果をさらに加工したり、複雑な計算を段階的に行ったりできるようになります!
学習メモ
SQL応用・パフォーマンス最適化 - Step 2