【さぶくえり】

サブクエリ(副問合せ) とは?

最終更新:
💡 SQLの中に入れ子で書く「もう一つのSELECT文」

SQLの中に入れ子で書かれたSELECT文のこと。外側のクエリの条件や値として内側のクエリの結果を利用でき、複雑な条件検索を1つのSQLで実現する。

📌 このページのポイント
サブクエリ:内側の結果を条件に SELECT * FROM users WHERE age > ( … ) SELECT AVG(age) FROM users users(仮例) A:30歳 B:40歳 C:50歳 内側の結果 平均40歳 条件に合う人 C:50歳 40歳を超える
30・40・50歳の平均は40歳。その平均を超える行はC(50歳)。上はSQLの入れ子、下の矢印は値を使う関係を示し、DB内部の実行順を保証するものではない。
ひよこ ひよこ
サブクエリってどんなときに使うの?
ペンギン先生 ペンギン先生
たとえば「平均年齢より上のユーザーを取得する」ときだよ。SELECT * FROM users WHERE age > (SELECT AVG(age) FROM users) と書くと、内側のSELECTが返す平均を外側の条件に使える。図の仮データは30・40・50歳なので、平均40歳を超える50歳の人が該当するね。
ひよこ ひよこ
内側が何行返してもいいの?
ペンギン先生 ペンギン先生
使い方によるよ。さっきの平均のように一つの値として使う「スカラーサブクエリ」は、1列で最大1行が必要なんだ。PostgreSQLでは複数行や複数列だとエラーになり、0行ならNULLになる。INやEXISTSは複数行の結果も扱えるよ。
ひよこ ひよこ
INとEXISTSって何が違うの?
ペンギン先生 ペンギン先生
WHERE id IN (SELECT user_id FROM orders) は、idと同じ値が内側の結果にあるかを調べる。WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id) は、そのユーザーに対応する注文の行が存在するかを調べるよ。大きさだけでどちらが速いと決めず、意味と実行計画を確認しよう。
ひよこ ひよこ
JOINとサブクエリはどう使い分けるの?
ペンギン先生 ペンギン先生
JOINは表を結び付けて列を取り出すのに向くよ。一方、EXISTSは対応する行があるかを条件にできる。あるユーザーに注文が2件あると、単純なJOINではそのユーザーが2行出ても、EXISTSなら元のユーザーの行は1行のまま。書き換えでは、このような重複の違いも確認するんだ。
ひよこ ひよこ
相関サブクエリってなに?
ペンギン先生 ペンギン先生
外側の値を参照するサブクエリだよ。さっきのEXISTSで、orders.user_idと外側のusers.idを比べる部分がその例だね。論理的には外側の行に依存するけど、DBが条件に応じて結合などへ変換する場合もある。必ず行数分だけ同じ処理をするとは限らず、EXPLAINで計画を見て、実際の時間も測ることが大切だよ。
もっと詳しく知りたい人へ

NOT INで「該当しない行」を取るとき、NULLが混ざるとどうなる?

一致する値がなくても内側の結果にNULLがあると、NOT INの結果は真ではなくNULL(不明)になるため、WHERE条件ではその行が選ばれません。たとえば3 NOT IN (1, NULL)は真になりません。NULLを除外するのか、対応する行が存在しないことをNOT EXISTSで調べるのか、外側のNULLも含めて求める結果を決めてください。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「サブクエリ」って出てきたら「SQLの中に書き、その結果を外側で使うSELECT文」と思えばだいたいOK!
📖 おまけ:英語の意味
「Subquery」 = 副(Sub)問合せ(Query)
💬 Subは「下位の」、Queryは「問合せ」。問合せの中に含まれる問合せという意味だよ

参考資料

← 用語集にもどる