SQLを学んでいると、「別のSQLで取得した結果を、さらに別のSQLで利用したい」という場面があります。

このようなときに使用するのが、**副問い合わせ(サブクエリ)**です。

今回は、サンプルテーブルを使って、SQLを実行しながら副問い合わせの動きを確認していきます。


1. 今回使用するテーブル

今回は、以下の2つのテーブルがすでに存在しているものとします。

employeeテーブル

employee_idemployee_namesalarydepartment_id
1田中30000010
2鈴木40000020
3佐藤50000020
4高橋35000010
5伊藤45000030

departmentテーブル

department_iddepartment_namelocation
10営業部東京
20開発部大阪
30総務部東京
40企画部東京

以降は、このデータを使って副問い合わせを実行します。


2. 副問い合わせとは

副問い合わせとは、SQL文の中に記述する別のSQL文です。

例えば、

全社員の平均給与より給与が高い社員を取得する

という処理を考えます。

まず、平均給与を取得します。

SELECT AVG(salary)
FROM employee;

実行結果は次のとおりです。

AVG(salary)
400000

平均給与は400,000円です。

この結果を利用して、

SELECT *
FROM employee
WHERE salary > 400000;

とすれば、平均給与より給与が高い社員を取得できます。

結果は、

employee_idemployee_namesalarydepartment_id
3佐藤50000020
5伊藤45000030

となります。

この2つのSQLを1つにまとめると、副問い合わせになります。

SELECT *
FROM employee
WHERE salary > (
    SELECT AVG(salary)
    FROM employee
);

実行結果

employee_idemployee_namesalarydepartment_id
3佐藤50000020
5伊藤45000030

この場合、

SELECT AVG(salary)
FROM employee

が副問い合わせです。

副問い合わせの結果である400000を、外側のSQLで利用しています。


3. INを使った副問い合わせ

次に、複数の結果を利用する場合を見てみます。

東京にある部署に所属する社員を取得する

まず、東京にある部署のIDを取得します。

SELECT department_id
FROM department
WHERE location = '東京';

実行結果

department_id
10
30

東京にある部署のIDは10と30です。

この結果を使って社員を検索します。

SELECT *
FROM employee
WHERE department_id IN (10, 30);

実行結果

employee_idemployee_namesalarydepartment_id
1田中30000010
4高橋35000010
5伊藤45000030

この処理を副問い合わせにすると、次のSQLになります。

SELECT *
FROM employee
WHERE department_id IN (
    SELECT department_id
    FROM department
    WHERE location = '東京'
);

実行結果

employee_idemployee_namesalarydepartment_id
1田中30000010
4高橋35000010
5伊藤45000030

ここでは副問い合わせの結果が10と30の複数行になるため、INを使用しています。


4. EXISTSを使った副問い合わせ

EXISTSは、条件に一致するデータが存在するかを確認するときに使用します。

例えば、

社員が所属している部署を取得する

場合は、次のように書けます。

SELECT *
FROM department d
WHERE EXISTS (
    SELECT 1
    FROM employee e
    WHERE e.department_id = d.department_id
);

実行結果

department_iddepartment_namelocation
10営業部東京
20開発部大阪
30総務部東京

企画部は結果に含まれていません。

これは、department_id = 40の社員がemployeeテーブルに存在しないためです。

つまりEXISTSは、

・社員が存在する場合は、その部署を取得する。
・社員が存在しない場合は、その部署を取得しない。

という処理になります。


5. FROM句で副問い合わせを使う

副問い合わせはFROM句にも使用できます。

例えば、部署ごとの平均給与を取得します。

SELECT
    department_id,
    AVG(salary) AS avg_salary
FROM employee
GROUP BY department_id;

実行結果

department_idavg_salary
10325000
20450000
30450000

この結果をさらに検索したい場合、FROM句に副問い合わせを記述できます。

SELECT *
FROM (
    SELECT
        department_id,
        AVG(salary) AS avg_salary
    FROM employee
    GROUP BY department_id
) AS department_salary
WHERE avg_salary >= 400000;

実行結果

department_idavg_salary
20450000
30450000

FROM句の副問い合わせによって、部署ごとの平均給与を一時的なテーブルのように扱っています。


6. 副問い合わせの使い分け

今回紹介した副問い合わせを整理すると、次のようになります。

種類用途
=など1つの値を取得する
IN複数の値を取得する
EXISTSデータが存在するか確認する
FROM句検索結果を一時的なテーブルとして利用する

特に初心者の方は、副問い合わせを見つけたら、まずカッコの中のSQLだけを確認することをおすすめします。

例えば、

SELECT *
FROM employee
WHERE salary > (
    SELECT AVG(salary)
    FROM employee
);

の場合は、まず、

SELECT AVG(salary)
FROM employee;

を実行すると考えます。

結果は、

400000

です。

その結果を外側のSQLに当てはめると、

SELECT *
FROM employee
WHERE salary > 400000;

となります。

このように、**「副問い合わせを先に実行して、その結果を外側のSQLで利用する」**と考えると理解しやすくなります。


7. まとめ

今回は、すでに存在するテーブルを使って、副問い合わせを実際に実行しました。

副問い合わせは、SQLの中に別のSQLを記述し、その結果を外側のSQLで利用する機能です。

代表的な使い方は以下のとおりです。

-- 1つの値を利用
WHERE salary > (
    SELECT AVG(salary)
    FROM employee
);
-- 複数の値を利用
WHERE department_id IN (
    SELECT department_id
    FROM department
    WHERE location = '東京'
);
-- 存在を確認
WHERE EXISTS (
    SELECT 1
    FROM employee e
    WHERE e.department_id = d.department_id
);

副問い合わせを理解するポイントは、内側のSQLがどのような結果を返し、その結果を外側のSQLがどのように利用しているかを確認することです。

まずはWHERE句の副問い合わせから実際に実行し、結果を確認しながら覚えていくと理解しやすくなります。

ここまで読んでいただき、ありがとうございます。もしこの記事の技術や考え方に少しでも興味を持っていただけたら、ネクストのエンジニアと気軽に話してみませんか。

  • 選考ではありません
  • 履歴書不要
  • 技術の話が中心
  • 所要時間30分程度
  • オンラインOK

エンジニアと話してみる

関連リンク

AI・クラウド・データ分析のご相談はネクスト株式会社までお問い合わせください。