本文へスキップ
BecomeCoder
ブログ一覧Wikiコース一覧

SQLのサブクエリ(副問い合わせ)とは|使い方をIN/EXISTSで解説

#SQL#サブクエリ#副問い合わせ#初心者

結論:サブクエリ(副問い合わせ)とは「クエリの中に別のクエリを入れる」書き方で、まず1本目のSELECTで値やリストを出し、それを2本目のWHEREで使う、と分けて考えると迷いません。 「◯◯より高い」「◯◯に含まれる」のように、条件そのものをデータベースに計算させたいときに使います。

このサイトのSQLレッスンは、すべてブラウザの中でそのままSQLを実行できます(無料・登録不要・環境構築なし)。読みながら手を動かすのがいちばん早いです。

サブクエリ=「クエリの中のクエリ」

サブクエリは、SELECT文の中に括弧 ( ) でくくって埋め込む、もう1つのSELECT文のことです。日本語では「副問い合わせ」とも呼びます。

たとえば「平均より高い価格の商品を出したい」とき、値を直接書くことはできません。平均がいくつかは、データを見るまで分からないからです。そこでこう書きます。

SELECT name, price
FROM products
WHERE price > (SELECT AVG(price) FROM products);

内側の (SELECT AVG(price) FROM products) が先に動いて平均値を1つ返し、外側のWHEREがその値を使って絞り込みます。「内側が先、外側が後」 という順番さえ押さえれば、あとは組み立てるだけです。

この基本形は、サブクエリ ― クエリの中のクエリ のレッスンでブラウザにそのままSQLを打ち込んで確かめられます。数字を書き換えて何度でも実行できるので、「内側だけ先に実行するとどうなるか」を自分の目で見てみてください。

WHEREの中で値と比べる

サブクエリがいちばん活躍するのはWHEREの中です。前提として、WHEREでの絞り込みそのものに不安がある人は、先に WHERE ― 条件で絞り込む をブラウザで一周しておくと、サブクエリがすっと入ってきます。

サブクエリが返すものは、大きく2種類に分けて考えると整理できます。

「返ってくるのは1個か、複数か」を意識するだけで、書くべき演算子が決まります。

IN サブクエリ ― リストに含まれるかで絞る

「東京の会員が出した注文だけ見たい」のように、別の表から条件のリストを作って、その中に含まれる行を選ぶ のが IN サブクエリです。

SELECT * FROM orders
WHERE member_id IN (SELECT id FROM members WHERE city = '東京');

内側が「東京の会員IDの一覧」を返し、外側が「その一覧に含まれる注文」を選びます。IN はもともとリストとの照合を行う演算子です。IN の基本(値をカンマ区切りで並べる書き方)に自信がなければ、DISTINCT・LIKE・IN・BETWEEN ― 絞り込みを広げる で先に手を動かしておくと、サブクエリ版がそのまま延長線上に見えます。

IN と EXISTS の使い分け

「別の表に一致する行があるか」を確かめる書き方には、IN のほかに EXISTS があります。考え方が少し違います。

SELECT * FROM members m
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.member_id = m.id);
-- 「注文を1件でも出したことがある会員」だけが残る

EXISTS のように、外側の行の値を内側で使うサブクエリを 相関サブクエリ と呼びます。少し難しく感じるところですが、相関サブクエリと EXISTS ― 行ごとに問い合わせる で、実際に行が1つずつ処理される様子をブラウザで実行しながら追えます。ここが腹落ちすると、サブクエリの理解が一段深くなります。

サブクエリと JOIN、どっちを使う?

「別の表とつなぐ」という点で、サブクエリは JOIN ― 2つの表を結びつける と役割が重なります。ざっくりした使い分けはこうです。

どちらでも書ける場面も多いので、まずは「結果に相手の列が要るか?」で選ぶと迷いません。両方を実際に書いて見比べると違いが体でわかります。

つまずきやすいところ

初心者が最初にぶつかる代表的なエラーが、比較のつもりのサブクエリが複数の列を返してしまう ケースです。

-- ✗ 内側が2列返しているので、= と比べられない
WHERE member_id = (SELECT id, name FROM members WHERE ...);

= ( ... ) で比べるサブクエリは 1列・1行だけ を返さなければいけません。原因と直し方は サブクエリの列数が合わない(sub-select returns N columns) にまとめてあります。似た形で「集計とGROUP BYがかみ合っていない」エラーもよく出るので、必要なら SQLのエラー逆引き をブックマークしておくと安心です。

もう一つ、IN サブクエリの内側にNULLが混ざると、期待とずれた結果になることがあります。NULLの扱いは NULL ― 「値が無い」を正しく扱う で押さえておくと、原因不明のハマりを避けられます。

次に読む

← ブログ一覧に戻る