SQLのサブクエリを完全ガイド!入れ子クエリの使い方を初心者向け解説
新人
「SQLで、ある条件に基づいてデータを取得する方法を知りたいです!」
先輩
「それなら、サブクエリを使うと便利だよ。サブクエリを使うと、あるクエリの結果を使って、さらに別のクエリを実行できるんだ。」
新人
「サブクエリって何ですか?」
先輩
「サブクエリは、SELECT文の中に入れ子になっているSELECT文のことだよ。例えば、最大の給与を持つ社員を探すときに使えるよ。」
1. サブクエリとは?
SQLのサブクエリ(入れ子クエリ)とは、SELECT文の中に別のSELECT文を含める方法です。
1. サブクエリを使うメリット
- 複雑な条件でデータを抽出できる
- SQLを分割して、可読性を向上させる
- テーブルを結合せずにデータを取得できる
サブクエリは、主に以下の3つの場所で使用されます。
- WHERE句(データの絞り込み)
- FROM句(サブクエリを仮想テーブルとして利用)
- SELECT句(特定の値を計算・取得)
今回は、最も基本的なWHERE句でサブクエリを使う方法を解説します。
2. WHERE句で使うサブクエリ(単純な例)
サブクエリをWHERE句で使用すると、特定の条件を満たすデータを取得できます。
1. 最高給与の社員を取得する
まず、全社員の中で最も給与が高い社員を取得するSQLを考えてみます。
SELECT * FROM employee
WHERE salary = (SELECT MAX(salary) FROM employee);
このSQLを実行すると、最も高い給与を持つ社員が取得されます。
| id | name | age | department | salary |
|---|---|---|---|---|
| 3 | 鈴木 一郎 | 35 | 開発 | 6000000 |
2. 営業部の平均給与以上の社員を取得する
営業部の平均給与より高い給与をもらっている社員を取得するSQLを作成します。
SELECT * FROM employee
WHERE salary > (SELECT AVG(salary) FROM employee WHERE department = '営業');
このSQLを実行すると、営業部の平均給与より高い給与を持つ社員が取得されます。
3. 他のテーブルのデータを条件にする
例えば、従業員の中で、1つでも注文をしたことがある人だけを取得する場合、サブクエリを使用してordersテーブルとemployeeテーブルを関連付けることができます。
SELECT * FROM employee
WHERE id IN (SELECT employee_id FROM orders);
このSQLを実行すると、注文履歴がある社員だけが取得されます。
このように、サブクエリを使うと、より柔軟な検索が可能になります。
4. FROM句で使うサブクエリ(サブクエリを仮想テーブルとして扱う)
サブクエリをFROM句で使用すると、サブクエリの結果を仮想テーブル(派生テーブル)として利用できます。
1. 部署ごとの平均給与を取得する
以下のSQLは、各部署の平均給与を計算し、それを基に新しいテーブルを作成して利用します。
SELECT department, average_salary
FROM (
SELECT department, AVG(salary) AS average_salary
FROM employee
GROUP BY department
) AS salary_table;
このSQLを実行すると、各部署の平均給与が取得できます。
| department | average_salary |
|---|---|
| 営業 | 4900000 |
| 開発 | 6000000 |
| 人事 | 4800000 |
このように、サブクエリを使って一時的なテーブルを作成し、それを元に新たなデータを取得できます。
5. SELECT句で使うサブクエリ(計算やランキングに活用)
サブクエリをSELECT句で使用すると、各行ごとに別の計算結果を取得できます。
1. 各社員の給与と部署の平均給与を一緒に表示する
SELECT id, name, salary,
(SELECT AVG(salary) FROM employee e2 WHERE e1.department = e2.department) AS department_avg_salary
FROM employee e1;
このSQLを実行すると、各社員の給与と同じ部署の平均給与が表示されます。
| id | name | salary | department_avg_salary |
|---|---|---|---|
| 1 | 田中 太郎 | 5000000 | 4900000 |
| 2 | 佐藤 花子 | 4200000 | 4900000 |
| 3 | 鈴木 一郎 | 6000000 | 6000000 |
このように、サブクエリをSELECT句で使用すると、個々の行に対する追加情報を取得できます。
6. サブクエリとJOINの違い(どちらを使うべきか)
サブクエリとJOINは、どちらもデータを取得する際に利用されますが、それぞれの特性があります。
1. サブクエリを使った場合
SELECT id, name, salary,
(SELECT AVG(salary) FROM employee e2 WHERE e1.department = e2.department) AS department_avg_salary
FROM employee e1;
このSQLは、各社員の給与と同じ部署の平均給与を取得しますが、社員ごとにサブクエリが実行されるため、パフォーマンスに影響を与える可能性があります。
2. JOINを使った場合
SELECT e1.id, e1.name, e1.salary, salary_table.average_salary
FROM employee e1
JOIN (
SELECT department, AVG(salary) AS average_salary
FROM employee
GROUP BY department
) AS salary_table
ON e1.department = salary_table.department;
このSQLでは、先に部署ごとの平均給与を計算し、それをJOINすることで、一度のクエリで効率的に取得できます。
3. サブクエリとJOINの使い分け
| 方法 | メリット | デメリット |
|---|---|---|
| サブクエリ | コードがシンプルで直感的 | パフォーマンスが悪くなることがある |
| JOIN | パフォーマンスが向上しやすい | コードが複雑になる |
基本的には、データの結合が多い場合はJOINを使用し、シンプルなデータ取得ならサブクエリを使うと良いでしょう。
7. 相関サブクエリとは?(外側のクエリと連携するサブクエリ)
SQLのサブクエリには、相関サブクエリという特別な形式があります。相関サブクエリは、外側のクエリ(親クエリ)の各行に対して個別に実行されるサブクエリです。
1. 各社員の所属する部署内での給与順位を取得する
例えば、各社員が所属する部署の中で給与が何番目に高いかを取得するには、相関サブクエリを使用します。
SELECT e1.id, e1.name, e1.department, e1.salary,
(SELECT COUNT(*) + 1
FROM employee e2
WHERE e2.department = e1.department
AND e2.salary > e1.salary) AS salary_rank
FROM employee e1
ORDER BY department, salary_rank;
このSQLを実行すると、各社員の給与の順位が取得できます。
| id | name | department | salary | salary_rank |
|---|---|---|---|---|
| 1 | 田中 太郎 | 営業 | 5000000 | 1 |
| 2 | 佐藤 花子 | 営業 | 4200000 | 2 |
| 3 | 鈴木 一郎 | 開発 | 6000000 | 1 |
2. 相関サブクエリの特性と注意点
メリット: 各行に対して柔軟な条件を適用できる。
デメリット: 行ごとにサブクエリが実行されるため、処理が遅くなりやすい。
8. サブクエリのパフォーマンス最適化(サブクエリ vs JOIN)
サブクエリは便利ですが、大量のデータを処理するとパフォーマンスが低下することがあります。そのため、場合によってはJOINを使った方が高速になることがあります。
1. 相関サブクエリの問題点
例えば、以下のSQLでは、各社員の部署内での最大給与を取得していますが、相関サブクエリを使用すると、社員ごとにサブクエリが実行されるため、パフォーマンスが悪くなります。
SELECT id, name, department, salary,
(SELECT MAX(salary) FROM employee e2 WHERE e2.department = e1.department) AS max_salary
FROM employee e1;
このSQLは、部署ごとに給与の最大値を求めるために、全社員のデータ分だけサブクエリが実行されます。
2. JOINを使って最適化する
同じ結果を得る場合でも、JOINを使うことでパフォーマンスを向上させることができます。
SELECT e1.id, e1.name, e1.department, e1.salary, salary_table.max_salary
FROM employee e1
JOIN (
SELECT department, MAX(salary) AS max_salary
FROM employee
GROUP BY department
) AS salary_table
ON e1.department = salary_table.department;
このSQLを実行すると、相関サブクエリを使わずに、より効率的に最大給与を取得できます。
3. サブクエリとJOINの比較
| 方法 | メリット | デメリット |
|---|---|---|
| サブクエリ | コードがシンプルで直感的 | パフォーマンスが低下することがある |
| JOIN | 高速で大規模データに適している | コードが複雑になる |
データ量が少ない場合はサブクエリでも問題ありませんが、大規模データを扱う場合はJOINの方が高速なので、適切に使い分けましょう。
9. 実践!サブクエリを活用したデータ取得のテクニック
最後に、サブクエリを活用した実践的なデータ取得方法を紹介します。
1. 直近3ヶ月の売上合計を取得
売上管理テーブルsalesがあり、最新3ヶ月の売上合計を求める場合、以下のサブクエリを使用できます。
SELECT SUM(amount) AS total_sales
FROM sales
WHERE sale_date >= (
SELECT DATE_SUB(MAX(sale_date), INTERVAL 3 MONTH) FROM sales
);
このSQLを実行すると、最新の売上日から3ヶ月間の売上合計が取得できます。
2. 各社員の所属部署内での給与割合を求める
各社員の給与が、同じ部署内の給与合計の何%を占めるかを求めるSQLです。
SELECT id, name, department, salary,
(salary / (SELECT SUM(salary) FROM employee e2 WHERE e2.department = e1.department)) * 100 AS salary_percentage
FROM employee e1;
このSQLを実行すると、各社員の給与の部署内での割合が算出されます。
このように、サブクエリを適切に使うことで、データの高度な分析が可能になります。
まとめ
この記事では、SQLのサブクエリを基礎から応用まで順を追って整理しながら学び、WHERE句、FROM句、SELECT句での具体的な活用方法、さらに相関サブクエリやJOINとの使い分けといった実践的な知識に触れてきました。サブクエリは「入れ子のSELECT文」として柔軟性の高いデータ抽出を可能にし、とくに複雑な条件を扱う場面や、テーブル結合を避けたい場面で強力に機能します。サブクエリは単純なフィルタリングから部署別平均給与の計算、さらには給与順位の評価や大規模データにおける検索条件の最適化など、多彩な用途で活用できるため、SQL学習者にとって欠かせない知識です。 また、サブクエリは「直感的で読みやすい」という利点を持つ一方で、相関サブクエリのように外側のクエリと行単位で結びつく場合はパフォーマンスが低下しやすく、そのようなケースではJOINを用いたほうが高速になることも確認しました。SQLのパフォーマンス特性を理解し、場面に応じた使い分けができることは業務でのデータ取得効率を大きく左右します。 さらに、FROM句サブクエリによる派生テーブルの生成やSELECT句による付加情報の計算など、実務でも活躍するテクニックを学ぶことで、データ分析・レポート作成の幅がより広がるはずです。ここでは理解を深めるため、記事内の流れと同じ形式で仮想テーブルを用いたサンプルSQLを改めて掲載しておきます。
サンプルプログラム:平均給与を基にランキング付き一覧を作成する
以下は、各社員の給与、所属部署の平均給与、さらに順位をまとめて取得するための例です。入れ子クエリを組み合わせることで、集計とランキングの両方を一つの結果にまとめています。
SELECT
e1.id,
e1.name,
e1.department,
e1.salary,
(SELECT AVG(salary)
FROM employee e2
WHERE e2.department = e1.department) AS department_avg_salary,
(SELECT COUNT(*) + 1
FROM employee e3
WHERE e3.department = e1.department
AND e3.salary > e1.salary) AS salary_rank
FROM employee e1
ORDER BY department, salary_rank;
部署の平均給与を求めるサブクエリ、給与順位を計算する相関サブクエリ、それぞれが役割を持ちながら単一の結果としてまとまる様子が分かります。このような組み立て方ができるようになると、複雑に見える業務要件にも柔軟に対応できるようになり、SQLの表現力が大きく広がります。
新卒エンジニア:「サブクエリって、最初は難しそうに感じたけれど、使いどころが分かるとすごく便利ですね!」
先輩社員:「そうだね。特に条件を柔軟に組み合わせたいときや、集計結果を別の条件に使いたいときには欠かせない技術なんだ。」
新卒エンジニア:「相関サブクエリと普通のサブクエリの違いも理解できました。行ごとに実行されるから重くなるっていう点も気をつけたいです。」
先輩社員:「その感覚が大事。JOINで代用できるかどうか考えることが、SQLの最適化の第一歩なんだよ。」
新卒エンジニア:「これから分析系のクエリを書くときにも、今回覚えたテクニックを活かしていきたいです!」
先輩社員:「ぜひ活用していこう。サブクエリを自在に使えるようになると、SQLの設計力が一段階アップするよ。」