複数のクエリを統合したい時は副問合せ(サブクエリ)を使います。
本記事では、副問合せ(サブクエリ)とは何か、基本的な使い方、SELECT句やWHERE句などで副問合せを使う方法などを具体例を交えて解説しています。
目次
副問合せ(サブクエリ)とは
副問合せとは、あるSELECT文で得られた結果を別のSELECT文で使うことを指します。すなわち、SELECT文の中でに入れ子構造の形でSELECT文が使われます。
副問合せという言葉の意味は下記のとおりです。
副問合せの「副」・・入れ子構造の中にあるSELECT文なので、全体を主(メイン)とした時の副(サブ)という意味
副問合せの「問合せ」・・SQLのクエリがそもそも問合せという意味
例えば、下記のようなクエリが副問合せになります。
()
で囲むことで、副問合せが使えます。クエリの中にクエリが書かれていることが分かります。
また、副問合せの別名をサブクエリと言います。
副問合せ(サブクエリ)の使いどころ
副問合せは二段階以上の集計が必要な場合などに使います。
例えば、「ユーザー情報を管理しているテーブルから最年長の人のレコードを全て取得する」場合を見てみましょう。
最年長の人の年齢だけを取得するのであれば、下記のクエリで実現できます。
SELECT MAX(age)
FROM users;
このクエリによって最年長の年齢は分かりますが、最年長の人が何人いるのか、最年長の人の名前の情報等は取得できません。
今回の例では下記2段階の集計が必要です。
- 最年長の人を取得する
- 最年長の人の全てのレコードを取得する
よって、このような場合に副問合せを用います。
SELECT *
FROM users
WHERE age = (
SELECT MAX(age)
FROM users
);
これで最年長の人のレコードを全て取得することができます。
考え方の流れは下記です。
SELECT MAX(age) FROM users
という副問合せで最年長の人の年齢を取得WHERE age = 最年長の人の年齢
という条件でusersテーブルに検索をかけるSELECT *
で条件に該当する全てのレコードを取得
ポイントは、副問合せのクエリが一番最初に実行されて、それから外側のクエリが実行されるということです。
ただし、副問合せを使うデメリットとしてクエリが重くなるという問題があります。もし、副問合せを使わずに実現できるのであれば極力そうしましょう。
それでは、具体的な副問合せの使用例を見ていきましょう。
サンプルデータ
下記のとおり、usersテーブルとscoreテーブルを用意します。
usersテーブル
id | name | age | address |
---|---|---|---|
1 | 山田 | 25 | 東京都 |
2 | 鈴木 | 34 | 神奈川県 |
3 | 佐藤 | 29 | 大阪府 |
4 | 佐々木 | 47 | 東京都 |
5 | 大野 | 38 | 大阪府 |
scoresテーブル
id | score | user_id |
---|---|---|
1 | 76 | 3 |
2 | 98 | 4 |
3 | 45 | 1 |
4 | 69 | 5 |
5 | 80 | 2 |
SELECT句を使った副問合せ
まず最初にSELECT句で副問合せを使う場合を見ていきます。
検索クエリ
usersテーブルの全ての情報を取得した上で、scoresテーブルからユーザーのスコアも取得する
SELECT
id,
name,
age,
(
SELECT score
FROM scores
WHERE users.id = scores.user_id
) AS score
FROM users;
下記の流れで考えていきます。
- usersテーブルの全ての情報を取得するため、
id
、name
、age
を指定 ()
で副問合せを開始- usersテーブルの
id
とscoresテーブルのuser_id
が一致するscoreカラムの値を取得する副問合せを書く - AS句を使ってカラムに
score
という名前をつける
ポイントはWHERE users.id = scores.user_id
の部分です。ここの条件によって、usersテーブルとscoresテーブルが紐づいてユーザーに応じたscore
を取得できるようになります。
実行結果
id | name | age | score |
---|---|---|---|
1 | 山田 | 25 | 45 |
2 | 鈴木 | 34 | 80 |
3 | 佐藤 | 29 | 76 |
4 | 佐々木 | 47 | 98 |
5 | 大野 | 38 | 69 |
usersテーブルの情報に加えて、usersテーブルに紐づいたscoreカラムを取得できました。
FROM句を使った副問合せ
次にFROM句で副問合せを使う場合を見ていきます。
検索クエリ
usersテーブルからユーザーの居住地と、同じ居住地に該当するユーザーの人数を取得する
SELECT address, user_count
FROM (
SELECT address, COUNT(*) AS user_count
FROM users
GROUP BY address
) AS table1;
副問合せの中でGROUP BY句を使ってusersテーブルのグループ化を行っています。
予め条件を定義しておきたい場合(今回の場合はグループ化)などにFROM句での副問合せは便利です。
実行結果
address | user_count |
---|---|
大阪府 | 2 |
東京都 | 2 |
神奈川県 | 1 |
居住地の情報と、その居住地に該当する人の人数を取得できました。
WHERE句を使った副問合せ
次に、WHERE句を使った検索条件で副問合せを使う場合を見ていきます。
下記2パターンに分けて解説します。
- 副問合せの実行結果が一つのレコードの場合
- 副問合せの実行結果が複数レコードの場合
副問合せの実行結果が一つのレコードの場合
検索クエリ
usersテーブルから最年長の人のユーザー情報を取得する
SELECT *
FROM users
WHERE age = (
SELECT MAX(age)
FROM users
);
下記の流れで考えていきます。
- 「最年長の人」を検索するために、
WHERE age = 最年長の年齢
と指定を行う - 最年長の年齢を取得するために副問合せを使う
MAX(age)
を指定してusersテーブルからageカラムの最大値を取得
実行結果
id | name | age | address |
---|---|---|---|
4 | 佐々木 | 47 | 東京都 |
usersテーブルから最年長のレコードを取得できました。
副問合せの実行結果が複数レコードの場合
先ほどは副問合せの結果がMAX(age)
と単独の値でしたが、次は複数の値を副問合せで取得する場合を見ていきます。
検索クエリ
スコアが80点以上のユーザー情報を取得する
SELECT *
FROM users
WHERE id IN (
SELECT user_id
FROM scores
WHERE score >= 80
);
下記の流れで考えていきます。
- 「スコアが80点以上の人」を検索するためにWHERE句を使う
- スコアが80点以上の人は複数存在する可能性があるためIN句を使って、
WHERE id IN ()
と指定 - IN句で指定する値を副問合せを使って取得する
- 副問合せではuser_idカラムを指定して、
WHERE score >= 80
と80点以上のレコードを指定
実行結果
id | name | age | address |
---|---|---|---|
2 | 鈴木 | 34 | 神奈川県 |
4 | 佐々木 | 47 | 東京都 |
80点以上の得点を取ったユーザー情報を取得できました。
内容のまとめ
- 副問合せあるSELECT文で得られた結果を別のSELECT文で使うこと
- 例えば、
SELECT * FROM ( SELECT カラム名 FROM テーブル名 )
の()
内が副問合せ - 副問合せの別名をサブクエリと言う
- 副問合せ(サブクエリ)は二段階以上の集計が必要な場合などに使う
- 副問合せはSELECT句、FROM句、WHERE句などで使える