メインクエリは外側の問い合わせ、サブクエリ(副問い合わせ)はその中に含める問い合わせです。「何を取り出すか」を外側で書き、条件に使う平均値などを内側の問い合わせで求めると、複雑な条件を整理できます。
平均点より高い生徒を取り出す例
次の生徒表で、全体平均を超える生徒を抽出します。点数にはNULLがないものとします。
| 名前 | スコア |
|---|---|
| Aさん | 60 |
| Bさん | 80 |
| Cさん | 100 |
SELECT name, score
FROM students
WHERE score > (SELECT AVG(score) FROM students);
ここでは表名をstudents、列名をname・scoreとします。内側は平均80を求め、外側はscoreが80より大きいCさん(100点)を返す、と読むと分かりやすくなります。80点のBさんは「超える」条件には入りません。
「必ず内側から実行」は言い切らない
上の例は結果の意味を理解するための読み方です。実際の実行順はDBMSの最適化により変わることがあります。サブクエリが必ず先に一度だけ実行される、あるいは必ず遅い、とは限りません。
置く場所と返す結果を対応させる
| 場所・使い方 | 注意点 |
|---|---|
| WHEREで値と比較 | =や>の右側で単一値として使うなら、1列・最大1行のスカラ副問い合わせにする |
| WHEREでIN | 一般的な単一列のINでは複数行の候補と照合できる |
| WHEREでEXISTS | 条件に合う行が一つでもあるかを調べる |
| SELECTの式 | 単一値を返す副問い合わせを計算列として使える |
| FROM | 問い合わせ結果を導出表として参照する。別名を付け、必要な列を選ぶ |
利用できる構文や別名の要件はDBMSで確認します。スカラ副問い合わせが0行ならNULLになり、複数行を返すとエラーになります。
相関サブクエリは外側の列を参照する
SELECT s.name, s.score
FROM students AS s
WHERE s.score > (
SELECT AVG(t.score)
FROM students AS t
WHERE t.class_id = s.class_id
);
この例ではclass_id列があり、各生徒が所属するクラスの平均を比較対象にしています。内側が外側のs.class_idを参照するため、相関サブクエリです。「クラスごとの平均と比較する」という意味と、実際に何回計算されるかは分けて考え、実行計画で確認します。
確認問題
「= (SELECT …)」の内側が2行を返しました。自動的にどちらか一方が選ばれますか?
解答・解説を見る
選ばれず、単一値を要求するスカラ副問い合わせでは複数行によるエラーになります。必要な条件に応じて集約で1行にするか、IN・EXISTSなどを検討します。
noteでサブクエリを他のSQLとつなげる
内側と外側の関係をつかんだら、SQL教材のSELECT・JOIN・GROUP BY・サブクエリをまとめて復習しましょう。単に書き方を覚えるだけでなく、返る行と列を追う練習につながります。
参考資料
この記事はSQLの説明です。WordPressなどのCMS内部で用いるメインクエリ・サブクエリという呼び方とは区別してください。
コメント