【SQL】副問合せ(サブクエリ)の使い方を初心者向けに解説

複数のクエリを統合したい時は副問合せ(サブクエリ)を使います。

本記事では、副問合せ(サブクエリ)とは何か、基本的な使い方、SELECT句やWHERE句などで副問合せを使う方法などを具体例を交えて解説しています。

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

副問合せとは、あるSELECT文で得られた結果を別のSELECT文で使うことを指します。すなわち、SELECT文の中でに入れ子構造の形でSELECT文が使われます。

副問合せという言葉の意味は下記のとおりです。

副問合せの「副」・・入れ子構造の中にあるSELECT文なので、全体を主(メイン)とした時の副(サブ)という意味
副問合せの「問合せ」・・SQLのクエリがそもそも問合せという意味

例えば、下記のようなクエリが副問合せになります。

()で囲むことで、副問合せが使えます。クエリの中にクエリが書かれていることが分かります。

また、副問合せの別名をサブクエリと言います。

副問合せ(サブクエリ)の使いどころ

副問合せは二段階以上の集計が必要な場合などに使います。

例えば、「ユーザー情報を管理しているテーブルから最年長の人のレコードを全て取得する」場合を見てみましょう。

最年長の人の年齢だけを取得するのであれば、下記のクエリで実現できます。

SQL
SELECT MAX(age)
FROM users;

このクエリによって最年長の年齢は分かりますが、最年長の人が何人いるのか、最年長の人の名前の情報等は取得できません。

今回の例では下記2段階の集計が必要です。

  • 最年長の人を取得する
  • 最年長の人の全てのレコードを取得する

よって、このような場合に副問合せを用います。

SQL
SELECT *
FROM users
WHERE age = (
  SELECT MAX(age)
  FROM users
);

これで最年長の人のレコードを全て取得することができます。

考え方の流れは下記です。

  1. SELECT MAX(age) FROM usersという副問合せで最年長の人の年齢を取得
  2. WHERE age = 最年長の人の年齢という条件でusersテーブルに検索をかける
  3. SELECT *で条件に該当する全てのレコードを取得

ポイントは、副問合せのクエリが一番最初に実行されて、それから外側のクエリが実行されるということです。

ただし、副問合せを使うデメリットとしてクエリが重くなるという問題があります。もし、副問合せを使わずに実現できるのであれば極力そうしましょう。

それでは、具体的な副問合せの使用例を見ていきましょう。

サンプルデータ

下記のとおり、usersテーブルとscoreテーブルを用意します。

usersテーブル

idnameageaddress
1山田25東京都
2鈴木34神奈川県
3佐藤29大阪府
4佐々木47東京都
5大野38大阪府
usersテーブル

scoresテーブル

idscoreuser_id
1763
2984
3451
4695
5802
scoresテーブル

SELECT句を使った副問合せ

まず最初にSELECT句で副問合せを使う場合を見ていきます。

検索クエリ

usersテーブルの全ての情報を取得した上で、scoresテーブルからユーザーのスコアも取得する

SQL
SELECT
  id,
  name,
  age,
  (
    SELECT score
    FROM scores
    WHERE users.id = scores.user_id
  ) AS score
FROM users;

下記の流れで考えていきます。

  1. usersテーブルの全ての情報を取得するため、idnameageを指定
  2. ()で副問合せを開始
  3. usersテーブルのidとscoresテーブルのuser_idが一致するscoreカラムの値を取得する副問合せを書く
  4. AS句を使ってカラムにscoreという名前をつける

ポイントはWHERE users.id = scores.user_idの部分です。ここの条件によって、usersテーブルとscoresテーブルが紐づいてユーザーに応じたscoreを取得できるようになります。

実行結果

idnameagescore
1山田2545
2鈴木3480
3佐藤2976
4佐々木4798
5大野3869

usersテーブルの情報に加えて、usersテーブルに紐づいたscoreカラムを取得できました。

FROM句を使った副問合せ

次にFROM句で副問合せを使う場合を見ていきます。

検索クエリ

usersテーブルからユーザーの居住地と、同じ居住地に該当するユーザーの人数を取得する

SQL
SELECT address, user_count
FROM (
  SELECT address, COUNT(*) AS user_count
  FROM users
  GROUP BY address
  ) AS table1;

副問合せの中でGROUP BY句を使ってusersテーブルのグループ化を行っています。

予め条件を定義しておきたい場合(今回の場合はグループ化)などにFROM句での副問合せは便利です。

実行結果

addressuser_count
大阪府2
東京都2
神奈川県1

居住地の情報と、その居住地に該当する人の人数を取得できました。

WHERE句を使った副問合せ

次に、WHERE句を使った検索条件で副問合せを使う場合を見ていきます。

下記2パターンに分けて解説します。

  • 副問合せの実行結果が一つのレコードの場合
  • 副問合せの実行結果が複数レコードの場合

副問合せの実行結果が一つのレコードの場合

検索クエリ

usersテーブルから最年長の人のユーザー情報を取得する

SQL
SELECT *
FROM users
WHERE age = (
  SELECT MAX(age)
  FROM users
);

下記の流れで考えていきます。

  1. 「最年長の人」を検索するために、WHERE age = 最年長の年齢と指定を行う
  2. 最年長の年齢を取得するために副問合せを使う
  3. MAX(age)を指定してusersテーブルからageカラムの最大値を取得

実行結果

idnameageaddress
4佐々木47東京都

usersテーブルから最年長のレコードを取得できました。

副問合せの実行結果が複数レコードの場合

先ほどは副問合せの結果がMAX(age)と単独の値でしたが、次は複数の値を副問合せで取得する場合を見ていきます。

検索クエリ

スコアが80点以上のユーザー情報を取得する

SQL
SELECT *
FROM users
WHERE id IN (
  SELECT user_id
  FROM scores
  WHERE score >= 80
);

下記の流れで考えていきます。

  1. 「スコアが80点以上の人」を検索するためにWHERE句を使う
  2. スコアが80点以上の人は複数存在する可能性があるためIN句を使って、WHERE id IN ()と指定
  3. IN句で指定する値を副問合せを使って取得する
  4. 副問合せではuser_idカラムを指定して、WHERE score >= 80と80点以上のレコードを指定

実行結果

idnameageaddress
2鈴木34神奈川県
4佐々木47東京都

80点以上の得点を取ったユーザー情報を取得できました。

内容のまとめ

  • 副問合せあるSELECT文で得られた結果を別のSELECT文で使うこと
  • 例えば、SELECT * FROM ( SELECT カラム名 FROM テーブル名 ) ()内が副問合せ
  • 副問合せの別名をサブクエリと言う
  • 副問合せ(サブクエリ)は二段階以上の集計が必要な場合などに使う
  • 副問合せはSELECT句、FROM句、WHERE句などで使える